From 5d7130bdcc46870f52956616ead7b7664f7fb5ad Mon Sep 17 00:00:00 2001 From: Raphael Wegmueller Date: Wed, 24 Jan 2024 08:23:29 +0100 Subject: [PATCH] fix: sharepoint filenames with comma and dot (#660) --- src/extension/module.js | 27 +++++++---- test/bulk-copy-urls.test.js | 61 +++++++++++++++++++++++- test/fixtures/admin-sharepoint-grid.html | 20 ++++++-- test/fixtures/admin-sharepoint.html | 14 ++++-- test/module.test.js | 10 ++-- test/utils.js | 2 +- 6 files changed, 113 insertions(+), 21 deletions(-) diff --git a/src/extension/module.js b/src/extension/module.js index 6b29fee89..268ee61ce 100644 --- a/src/extension/module.js +++ b/src/extension/module.js @@ -1590,15 +1590,21 @@ import sampleRUM from './rum.js'; if (['/', '*', '\\', '!', '?'].find((pattern) => path.includes(pattern))) { return `!ILLEGAL!_${path}`; } - const nameParts = path.split('.'); - let [file, ext] = nameParts; - if (isSharePointFolder(sk, sk.location) && ext === 'docx') { + let file = path; + let ext = ''; + const lastDot = path.lastIndexOf('.'); + if (lastDot >= 0) { + // cut off extension + file = path.substring(0, lastDot); + ext = path.substring(path.lastIndexOf('.')); + } + if (isSharePointFolder(sk, sk.location) && type === 'docx') { // omit docx extension on sharepoint ext = ''; } if (type === 'xlsx' || type.includes('vnd.google-apps.spreadsheet')) { // use json extension for spreadsheets - ext = 'json'; + ext = '.json'; } if (file === 'index') { // folder root @@ -1610,7 +1616,7 @@ import sampleRUM from './rum.js'; .replace(/[\u0300-\u036f]/g, '') .replace(/[^a-z0-9]+/g, '-') .replace(/^-|-$/g, ''); - return `${folder}${folder.endsWith('/') ? '' : '/'}${file}${ext ? `.${ext}` : ''}`; + return `${folder}${folder.endsWith('/') ? '' : '/'}${file}${ext}`; }; const validateWebPaths = (paths) => { @@ -1646,12 +1652,13 @@ import sampleRUM from './rum.js'; && !row.querySelector('svg')?.parentElement.className.toLowerCase().includes('folder')) // extract file name and type .map((row) => { - const [path, type] = (row.getAttribute('aria-label') || row.querySelector('span')?.textContent) - ?.split(',') - .map((detail) => detail.trim()) || []; + const info = row.getAttribute('aria-label') || row.querySelector('span')?.textContent; + // info format: bla.docx, docx File, Private, Modified 8/28/2023, edited by Jane, 1 KB + const type = info.match(/, ([a-z0-9]+) File,/)?.[1]; + const path = type && info.split(`, ${type} File,`)[0]; return { path, - type: type?.split(' ')[0], + type, }; }) // validate selection @@ -3191,7 +3198,7 @@ import sampleRUM from './rum.js'; .catch(({ message }) => { this.status.error = message; const modal = { - message: message.startsWith('error_') ? i18n(this, message) : [ + message: i18n(this, message) || [ i18n(this, 'error_status_fatal'), 'https://status.adobe.com/', ], diff --git a/test/bulk-copy-urls.test.js b/test/bulk-copy-urls.test.js index 0d053c56b..03f209270 100644 --- a/test/bulk-copy-urls.test.js +++ b/test/bulk-copy-urls.test.js @@ -228,11 +228,70 @@ describe('Test bulk copy URLs plugin', () => { loadModule: true, }).run(); assert.ok( - clipboardText.endsWith('.json'), + clipboardText.endsWith('spreadsheet.json'), `Preview URL does not have json extension: ${clipboardText}`, ); }); + it('Bulk copy preview URLs plugin handles file name with comma or dot in sharepoint views', async () => { + const { setup } = TESTS[0]; + nock.sidekick(setup, { + persist: true, + }); + nock.admin(setup, { + route: 'status', + type: 'admin', + persist: true, + }); + const views = [ + { + view: 'list', + fixture: 'admin-sharepoint.html', + }, + { + view: 'grid', + fixture: 'admin-sharepoint-grid.html', + }, + ]; + while (views.length > 0) { + const { view, fixture } = views.shift(); + // eslint-disable-next-line no-await-in-loop + const { checkPageResult: clipboardText } = await new SidekickTest({ + browser, + page, + fixture, + sidekickConfig: setup.sidekickConfig, + plugin: 'bulk-copy-preview-urls', + // pluginSleep: 1000, + pre: (p) => p.evaluate(() => { + // deselect all + document.getElementById('file-pdf').click(); + document.getElementById('file-word').click(); + // select only files with comma and dot + document.getElementById('file-comma').click(); + document.getElementById('file-dot').click(); + }), + post: (p) => p.evaluate(() => { + window.hlx.clipboardText = 'dummy'; + window.navigator.clipboard.writeText = (text) => { + window.hlx.clipboardText = text; + }; + }), + checkPage: (p) => p.evaluate(() => window.hlx.clipboardText), + loadModule: true, + }).run(setup.getUrl('edit', 'admin')); + const [fileComma, fileDot] = clipboardText.split('\n'); + assert.ok( + fileComma.endsWith('/document-new'), + `Unexpected preview URL for file with comma in ${view} view: ${fileComma}`, + ); + assert.ok( + fileDot.endsWith('/document-other'), + `Unexpected preview URL for file with dot in ${view} view: ${fileDot}`, + ); + } + }); + TESTS.forEach(({ env, fixture, setup }) => { it(`Bulk copy preview URLs plugin copies preview URLs for existing selection to clipboard in ${env}`, async () => { const { owner, repo, ref } = setup.sidekickConfig; diff --git a/test/fixtures/admin-sharepoint-grid.html b/test/fixtures/admin-sharepoint-grid.html index 84d95d323..e3b97e468 100644 --- a/test/fixtures/admin-sharepoint-grid.html +++ b/test/fixtures/admin-sharepoint-grid.html @@ -12,26 +12,40 @@
folder
- file.pdf, pdf + file.pdf, pdf File, Private
file.pdf
- document.docx, docx File + document.docx, docx File, Private
document.docx
- spreadsheet.xlsx, xlsx File + spreadsheet.xlsx, xlsx File, Private
spreadsheet.xlsx
+
+ document, new.docx, docx File, Private + + + +
document, new.docx
+
+
+ document.other.docx, docx File, Private + + + +
document, new.docx
+
diff --git a/test/fixtures/admin-sharepoint.html b/test/fixtures/admin-sharepoint.html index d95b34811..f584b9a12 100644 --- a/test/fixtures/admin-sharepoint.html +++ b/test/fixtures/admin-sharepoint.html @@ -15,18 +15,26 @@ -
+
-
+
-
+
+
+ + +
+
+ + +
diff --git a/test/module.test.js b/test/module.test.js index 6fe8af66f..3b9503384 100644 --- a/test/module.test.js +++ b/test/module.test.js @@ -89,6 +89,7 @@ describe('Test sidekick', () => { const setup = new Setup('blog'); const { sidekickConfig } = setup; nock.sidekick(setup, { persist: true }); + nock.admin(setup); const { checkPageResult } = await new SidekickTest({ browser, page, @@ -125,6 +126,7 @@ describe('Test sidekick', () => { { status: 403, body: 'Forbidden' }, { status: 500, body: 'Server error' }, { status: 504, body: 'Gateway timeout' }, + { status: undefined, body: 'Network error' }, ]; nock('https://admin.hlx.page') .get('/status/adobe/blog/main/en/topics/bla?editUrl=auto') @@ -134,7 +136,9 @@ describe('Test sidekick', () => { .get('/status/adobe/blog/main/en/topics/bla?editUrl=auto') .reply(500) .get('/status/adobe/blog/main/en/topics/bla?editUrl=auto') - .reply(504); + .reply(504) + .get('/status/adobe/blog/main/en/topics/bla?editUrl=auto') + .reply(503); nock.sidekick(new Setup('blog'), { persist: true }); // will be called multiple times const test = new SidekickTest({ browser, @@ -148,7 +152,7 @@ describe('Test sidekick', () => { }), }); while (errors.length) { - const { status } = errors.shift(); + const { status = 'https://status.adobe.com' } = errors.shift(); // eslint-disable-next-line no-await-in-loop const { notification, checkPageResult } = await test.run(); const sidekick = checkPageResult; @@ -770,8 +774,8 @@ describe('Test sidekick', () => { it('Hides notifications on overlay click', async () => { // hides sticky modal on overlay click const setup = new Setup('blog'); - nock.admin(setup); nock.sidekick(setup); + nock.admin(setup); const { checkPageResult } = await new SidekickTest({ browser, page, diff --git a/test/utils.js b/test/utils.js index 63a11ca58..cdd61f6e4 100644 --- a/test/utils.js +++ b/test/utils.js @@ -733,7 +733,7 @@ export function Nock() { n.persist(); } return n - .get(/.*/) + .get(/\/sidekick\/.*/) .optionally() .reply(() => (setup ? [200, configJson || setup.configJson]