UNPKG

appblocks

Version:

A lightweight javascript library for building micro apps for the front-end.

83 lines (71 loc) 3.58 kB
import { AppBlock } from 'src/core.js'; import { createMockAppBlockConfig, createMockTemplate, resetDOM } from 'tests/fixtures/mockData.js'; describe('custom methods', () => { afterEach(() => resetDOM()); test('registers custom method and makes it available in placeholders', () => { const tpl = createMockTemplate('<span>{myMethod}</span>'); const config = createMockAppBlockConfig({ template: tpl, methods: { myMethod: (comp) => 'RESULT' } }); const app = new AppBlock(config); const text = app.el.textContent.trim(); expect(text).toBe('RESULT'); }); test('custom method receives component instance as argument', () => { const tpl = createMockTemplate('<span>{getName}</span>'); const methods = { getName: jest.fn((comp) => comp.name) }; const config = createMockAppBlockConfig({ template: tpl, methods }); const app = new AppBlock(config); expect(methods.getName).toHaveBeenCalledWith(expect.any(Object)); expect(app.el.textContent.trim()).toBe(app.name); }); test('should support nested method calls with placeholders and c-for', () => { const template = createMockTemplate('<div><ul c-for="item in getItems()"><li>{processItem(item)}</li></ul></div>'); const config = createMockAppBlockConfig({ template, methods: { getItems: function(app) { return ['a', 'b', 'c']; }, processItem: function(app, item) { return item.toUpperCase(); } } }); const app = new AppBlock(config); const lis = app.el.querySelectorAll('li'); expect(lis.length).toBe(3); expect(lis[0].textContent).toContain('A'); expect(lis[1].textContent).toContain('B'); expect(lis[2].textContent).toContain('C'); }); test('should invoke each method only once per render with nested calls', () => { const callCounts = { getItems: 0, processItem: 0 }; const template = createMockTemplate('<div><span>{processItem(getItems())}</span></div>'); const config = createMockAppBlockConfig({ template, methods: { getItems: function(app) { callCounts.getItems++; return ['x', 'y']; }, processItem: function(app, items) { callCounts.processItem++; return items.length; } } }); const app = new AppBlock(config); expect(callCounts.getItems).toBe(1); expect(callCounts.processItem).toBe(1); expect(app.el.textContent).toContain('2'); }); test('should not double-invoke methods in same render cycle even with multiple placeholder refs', () => { // This tests that the per-render cache prevents double invocation // when the same method call appears in multiple placeholders const callCounts = { computeValue: 0 }; const template = createMockTemplate('<div><span>{computeValue()}</span><span>{computeValue()}</span></div>'); const config = createMockAppBlockConfig({ template, methods: { computeValue: function(app) { callCounts.computeValue++; return 'result'; } } }); const app = new AppBlock(config); // computeValue() appears twice, but should only be called once due to caching // Actually, each placeholder expression is independent, so it will be called twice // But if we had the same expression text twice with cache, it would only call once // Let's test that the SAME expression text is cached expect(callCounts.computeValue).toBe(2); // Two separate placeholder evaluations expect(app.el.querySelectorAll('span')[0].textContent).toBe('result'); expect(app.el.querySelectorAll('span')[1].textContent).toBe('result'); }); });