UNPKG

apostrophe

Version:
575 lines (498 loc) • 18 kB
const t = require('../test-lib/test.js'); const assert = require('assert'); const { JSDOM } = require('jsdom'); describe('Widgets', function() { const getRenderArgs = (req, page) => ({ outerLayout: '@apostrophecms/template:outerLayout.html', permissions: req.user && (req.user._permissions || {}), scene: 'apos', refreshing: false, query: req.query, url: req.url, page }); let apos; let req; let homePath; this.timeout(t.timeout); before(async function() { apos = await t.create({ root: module, modules: { 'args-bad-page': {}, 'args-good-page': {}, 'args-widget': {}, 'placeholder-page': {}, 'placeholder-widget': {} } }); req = apos.task.getAnonReq({ query: { aposEdit: '1' } }); const home = await apos.page.find(req, { level: 0 }).toObject(); homePath = home._id.replace(':en:published', ''); }); after(function() { return t.destroy(apos); }); describe('area tag', function() { let testItems = []; before(async function() { testItems = [ { _id: 'goodPageId:en:published', aposLocale: 'en:published', aposDocId: 'goodPageId', type: 'args-good-page', slug: '/good-page', visibility: 'public', path: `${homePath}/good-page`, level: 1, rank: 0, metaType: 'doc', main: { _id: 'randomAreaId1', items: [ { _id: 'randomWidgetId1', snippet: 'You can control what happens when the text reaches the edges of its content area using its attributes.', metaType: 'widget', type: 'args' } ], metaType: 'area' } }, { _id: 'badPageId:en:published', aposLocale: 'en:published', aposDocId: 'badPageId', type: 'args-bad-page', slug: '/bad-page', visibility: 'public', path: `${homePath}/bad-page`, level: 1, rank: 0, metaType: 'doc', main: { _id: 'randomAreaId2', items: [ { _id: 'randomWidgetId2', snippet: 'You can control what happens when the text reaches the edges of its content area using its attributes.', metaType: 'widget', type: 'args' } ], metaType: 'area' } } ]; await apos.doc.db.insertMany(testItems.map(item => ({ ...item, aposLocale: item.aposLocale.replace(':published', ':draft'), _id: item._id.replace(':published', ':draft') }))); await apos.doc.db.insertMany(testItems); }); after(async function() { await apos.doc.db.deleteMany({ aposDocId: { $in: testItems.map(item => item.aposDocId) } }); }); it('should be able to render page template with well constructed area tag', async function() { const goodPageDoc = await apos.page.find(req, { slug: '/good-page' }).toObject(); const args = getRenderArgs(req, goodPageDoc); const result = await apos.modules['args-good-page'].render(req, 'page', args); assert(result.includes('<h2>Good args page</h2>')); assert(result.includes('<p>You can control what happens when the text reaches the edges of its content area using its attributes.</p>')); assert(result.includes('<li>color: 🟣</li>')); }); it('should error while trying to render page template with poorly constructed area tag', async function() { const badPageDoc = await apos.page.find(req, { slug: '/bad-page' }).toObject(); const args = getRenderArgs(req, badPageDoc); try { await apos.modules['args-bad-page'].render(req, 'page', args); assert(false); } catch (error) { assert(error.toString().includes('Too many arguments were passed')); } }); }); describe('placeholders', function() { const insertPage = async (apos, homePath, widgets) => { const page = { _id: 'placeholder-page:en:published', aposLocale: 'en:published', aposDocId: 'placeholder-page', type: 'placeholder-page', slug: '/placeholder-page', visibility: 'public', path: `${homePath}/placeholder-page`, level: 1, rank: 0, metaType: 'doc', main: { _id: 'area1', items: widgets, metaType: 'area' } }; await apos.doc.db.insertOne(page); await apos.doc.db.insertOne({ ...page, aposLocale: page.aposLocale.replace(':published', ':draft'), _id: page._id.replace(':published', ':draft') }); }; const deletePage = async (apos, page) => { await apos.doc.db.deleteMany({ aposDocId: page.aposDocId }); }; describe('custom widget', function() { const widgetBaseData = { metaType: 'widget', type: 'placeholder' }; const widgetData = { ...widgetBaseData, string: 'Some string', integer: 2, float: 2.2, date: '2022-09-21', time: '15:39:12' }; let page; let result; before(async function() { const widgets = [ { _id: 'widget1', ...widgetBaseData, aposPlaceholder: true }, { _id: 'widget2', ...widgetBaseData, aposPlaceholder: false }, { _id: 'widget3', ...widgetBaseData }, { _id: 'widget4', ...widgetData } ]; await insertPage(apos, homePath, widgets); page = await apos.page.find(req, { slug: '/placeholder-page' }).toObject(); const args = getRenderArgs(req, page); result = await apos.modules['placeholder-page'].render(req, 'page', args); }); after(async function() { await deletePage(apos, page); }); it('should render the placeholders when widget\'s `aposPlaceholder` doc field is `true`', function() { assert(result.includes('<li>widget1 - aposPlaceholder: true</li>')); assert(result.includes('<li>widget1 - string: String PLACEHOLDER</li>')); assert(result.includes('<li>widget1 - integer: 0</li>')); assert(result.includes('<li>widget1 - float: 0.1</li>')); assert(result.includes('<li>widget1 - date: YYYY-MM-DD</li>')); assert(result.includes('<li>widget1 - time: HH:MM:SS</li>')); }); it('should not render the placeholders when widget\'s `aposPlaceholder` doc field is `false`', function() { assert(result.includes('<li>widget2 - aposPlaceholder: false</li>')); assert(!result.includes('<li>widget2 - string: String PLACEHOLDER</li>')); assert(!result.includes('<li>widget2 - integer: 0</li>')); assert(!result.includes('<li>widget2 - float: 0.1</li>')); assert(!result.includes('<li>widget2 - date: YYYY-MM-DD</li>')); assert(!result.includes('<li>widget2 - time: HH:MM:SS</li>')); }); it('should not render the placeholders when widget\'s `aposPlaceholder` doc field is not defined', function() { assert(!result.includes('<li>widget3 - string: String PLACEHOLDER</li>')); assert(!result.includes('<li>widget3 - integer: 0</li>')); assert(!result.includes('<li>widget3 - float: 0.1</li>')); assert(!result.includes('<li>widget3 - date: YYYY-MM-DD</li>')); assert(!result.includes('<li>widget3 - time: HH:MM:SS</li>')); assert(result.includes('<li>widget4 - string: Some string</li>')); assert(result.includes('<li>widget4 - integer: 2</li>')); assert(result.includes('<li>widget4 - float: 2.2</li>')); assert(result.includes('<li>widget4 - date: 2022-09-21</li>')); assert(result.includes('<li>widget4 - time: 15:39:12</li>')); }); it('should not render the placeholders on preview mode', async function() { const { aposEdit, ...query } = req.query; const _nonEditingReq = { ...req, query }; const args = getRenderArgs(_nonEditingReq, page); const _result = await apos.modules['placeholder-page'].render(_nonEditingReq, 'page', args); assert(!_result.includes('widget1')); }); }); const mediaWidgetTypeToAssertion = { video: { placeholderUrlOverride: 'https://vimeo.com/57946935', assertAposPlaceholderTrue(document) { const videoWrapperNodes = document.querySelectorAll('[data-apos-video-widget]'); assert(videoWrapperNodes.length === 1); assert(videoWrapperNodes[0].dataset.aposVideoUrl === 'https://youtu.be/Q5UX9yexEyM'); }, assertPreviewMode(document) { const videoWrapperNodes = document.querySelectorAll('[data-apos-video-widget]'); assert(videoWrapperNodes.length === 0); }, assertFalsyPlaceholderUrl(document) { const videoWrapperNodes = document.querySelectorAll('[data-apos-video-widget]'); assert(videoWrapperNodes.length === 0); }, assertPlaceholderUrlOverride(document) { const videoWrapperNodes = document.querySelectorAll('[data-apos-video-widget]'); assert(videoWrapperNodes.length === 1); assert(videoWrapperNodes[0].dataset.aposVideoUrl === 'https://vimeo.com/57946935'); } } }; Object.entries(mediaWidgetTypeToAssertion).forEach(([ type, { placeholderUrlOverride, assertAposPlaceholderTrue, assertPreviewMode, assertFalsyPlaceholderUrl, assertPlaceholderUrlOverride } ]) => { describe(`${type} widget`, function() { const widgetBaseData = { metaType: 'widget', type: `@apostrophecms/${type}` }; const widgets = [ { _id: 'widget1', ...widgetBaseData, aposPlaceholder: true }, { _id: 'widget2', ...widgetBaseData, aposPlaceholder: false }, { _id: 'widget3', ...widgetBaseData } ]; let page; let result; before(async function() { await insertPage(apos, homePath, widgets); page = await apos.page.find(req, { slug: '/placeholder-page' }).toObject(); const args = getRenderArgs(req, page); result = await apos.modules['placeholder-page'].render(req, 'page', args); }); after(async function() { await deletePage(apos, page); }); it('should render the placeholder only when widget\'s `aposPlaceholder` doc field is `true`', function() { const { document } = new JSDOM(result).window; assertAposPlaceholderTrue(document); }); it('should not render the placeholders on preview mode', async function() { const { aposEdit, ...query } = req.query; const _nonEditingReq = { ...req, query }; const args = getRenderArgs(_nonEditingReq, page); const _result = await apos.modules['placeholder-page'].render(_nonEditingReq, 'page', args); const { document } = new JSDOM(_result).window; assertPreviewMode(document); }); describe('placeholderUrl - falsy', function() { let _apos; let _page; let _result; before(async function() { // Recreate local apos instance with falsy `placeholderUrl` option // set to widget module _apos = await t.create({ root: module, modules: { 'placeholder-page': {}, [`@apostrophecms/${type}-widget`]: { options: { placeholderUrl: null, placeholderImage: null } } } }); const _req = _apos.task.getAnonReq({ query: { aposEdit: '1' } }); const home = await _apos.page.find(_req, { level: 0 }).toObject(); const _homePath = home._id.replace(':en:published', ''); await insertPage(_apos, _homePath, widgets); _page = await _apos.page.find(_req, { slug: '/placeholder-page' }).toObject(); const args = getRenderArgs(_req, _page); _result = await _apos.modules['placeholder-page'].render(_req, 'page', args); }); after(async function() { await deletePage(_apos, _page); await t.destroy(_apos); }); it('should not render the placeholder when widget\'s module `placeholderUrl` option is falsy', function() { const { document } = new JSDOM(_result).window; assertFalsyPlaceholderUrl(document); }); }); describe('placeholderUrl - override', function() { let _apos; let _page; let _result; before(async function() { // Recreate local apos instance with falsy `placeholderUrl` option // set to widget module _apos = await t.create({ root: module, modules: { 'placeholder-page': {}, [`@apostrophecms/${type}-widget`]: { options: { placeholderUrl: placeholderUrlOverride } } } }); const _req = _apos.task.getAnonReq({ query: { aposEdit: '1' } }); const home = await _apos.page.find(_req, { level: 0 }).toObject(); const _homePath = home._id.replace(':en:published', ''); await insertPage(_apos, _homePath, widgets); _page = await _apos.page.find(_req, { slug: '/placeholder-page' }).toObject(); const args = getRenderArgs(_req, _page); _result = await _apos.modules['placeholder-page'].render(_req, 'page', args); }); after(async function() { await deletePage(_apos, _page); await t.destroy(_apos); }); it('should render the placeholder set to the widget\'s module `placeholderUrl` override', function() { const { document } = new JSDOM(_result).window; assertPlaceholderUrlOverride(document); }); }); }); }); }); describe('Widget Operations', function() { let _apos; before(async function() { _apos = await t.create({ root: module, modules: { 'test1-widget': { extend: '@apostrophecms/widget-type', widgetOperations: { add: { operation1: { label: 'Operation 1', icon: 'image-edit-outline', modal: 'FakeModal', tooltip: 'tooltip' } } } }, 'test2-widget': { extend: 'test1-widget' }, 'test-permission-widget': { extend: '@apostrophecms/widget-type', widgetOperations: { add: { operation: { label: 'Operation', icon: 'some-icon', modal: 'AposSomeModal', permission: { action: 'delete', type: 'article' } } } } } } }); }); after(function() { return t.destroy(_apos); }); // todo it('should support custom widget operations and inherit them from extended modules', function() { const test1Widget = _apos.modules['test1-widget']; const test2Widget = _apos.modules['test2-widget']; const expectedOperations = [ { name: 'operation1', label: 'Operation 1', icon: 'image-edit-outline', modal: 'FakeModal', tooltip: 'tooltip' } ]; const filterNativeOperations = (operations) => operations .filter((operation) => !operation.nativeAction); const expected = { test1: expectedOperations, test2: expectedOperations }; const actual = { test1: filterNativeOperations(test1Widget.widgetOperations), test2: filterNativeOperations(test2Widget.widgetOperations) }; assert.deepEqual(actual, expected); }); it('should handle widget operations with custom permissions', function() { const operation = { name: 'operation', modal: 'AposSomeModal', label: 'Operation', icon: 'some-icon', permission: { action: 'delete', type: 'article' } }; const permissionWidget = _apos.modules['test-permission-widget']; const adminBrowserData = permissionWidget.getBrowserData(_apos.task.getReq()); const contribBrowserData = permissionWidget.getBrowserData( _apos.task.getContributorReq() ); const filterNativeOperations = (operations) => operations .filter((operation) => !operation.nativeAction); const actual = { admin: filterNativeOperations(adminBrowserData.widgetOperations), contributor: filterNativeOperations(contribBrowserData.widgetOperations) }; const expected = { admin: [ operation ], contributor: [] }; assert.deepEqual(actual, expected); }); }); });