diff --git a/.github/workflows/reusable-app-prod.yml b/.github/workflows/reusable-app-prod.yml index d560e6a8a43..8458f2a0fdf 100644 --- a/.github/workflows/reusable-app-prod.yml +++ b/.github/workflows/reusable-app-prod.yml @@ -213,7 +213,7 @@ jobs: fail-fast: false matrix: # List string expressions that is comma separated ids of tests in "test/cypress/integration" - spec-group: ['21', '23', '30', '50'] + spec-group: ['21', '30', '50'] services: mongodb: diff --git a/apps/app/test/cypress/e2e/23-editor/assets/example.txt b/apps/app/playwright/23-editor/assets/example.txt similarity index 100% rename from apps/app/test/cypress/e2e/23-editor/assets/example.txt rename to apps/app/playwright/23-editor/assets/example.txt diff --git a/apps/app/playwright/23-editor/with-navigation.spec.ts b/apps/app/playwright/23-editor/with-navigation.spec.ts new file mode 100644 index 00000000000..58650486964 --- /dev/null +++ b/apps/app/playwright/23-editor/with-navigation.spec.ts @@ -0,0 +1,113 @@ +import { readFileSync } from 'fs'; +import path from 'path'; + +import { test, expect, type Page } from '@playwright/test'; + +/** + * for the issues: + * @see https://redmine.weseek.co.jp/issues/122040 + * @see https://redmine.weseek.co.jp/issues/124281 + */ +test('should not be cleared and should prevent GrantSelector from modified', async({ page }) => { + await page.goto('/Sandbox/for-122040'); + + // Open Editor + await page.getByTestId('editor-button').click(); + await expect(page.getByTestId('grw-editor-navbar-bottom')).toBeVisible(); + + // Open GrantSelector and select "only me" + await page.getByTestId('grw-grant-selector').click(); + const dropdownMenu = page.getByTestId('grw-grant-selector-dropdown-menu'); + await expect(dropdownMenu).toBeVisible(); + await dropdownMenu.locator('.dropdown-item').nth(2).click(); + await expect(page.getByTestId('grw-grant-selector')).toContainText('Only me'); + + // Upload attachment + const filePath = path.resolve(__dirname, '../23-editor/assets/example.txt'); + const buffer = readFileSync(filePath).toString('base64'); + const dataTransfer = await page.evaluateHandle( + async({ bufferData, localFileName, localFileType }) => { + const dt = new DataTransfer(); + + const blobData = await fetch(bufferData).then(res => res.blob()); + + const file = new File([blobData], localFileName, { + type: localFileType, + }); + dt.items.add(file); + return dt; + }, + { + bufferData: `data:application/octet-stream;base64,${buffer}`, + localFileName: 'sample.tst', + localFileType: 'application/octet-stream', + }, + ); + await page.locator('.dropzone').first().dispatchEvent('drop', { dataTransfer }); + await expect(page.getByTestId('page-editor-preview-body').getByTestId('rich-attachment')).toBeVisible(); + + // Save page + await page.getByTestId('save-page-btn').click(); + + // Expect grant not to be reset after uploading an attachment + await expect(page.getByTestId('page-grant-alert')).toContainText('Browsing of this page is restricted'); +}); + +const appendTextToEditorUntilContains = async(page: Page, text: string) => { + await page.locator('.cm-content').fill(text); + await expect(page.getByTestId('page-editor-preview-body')).toContainText(text); +}; + +/** + * for the issue: + * @see https://redmine.weseek.co.jp/issues/115285 + */ +test('Successfully updating the page body', async({ page }) => { + const page1Path = '/Sandbox/for-115285/page1'; + const page2Path = '/Sandbox/for-115285/page2'; + + const page1Body = 'Hello'; + const page2Body = 'World'; + + + await page.goto(page1Path); + + // Open Editor (page1) + await page.getByTestId('editor-button').click(); + await expect(page.getByTestId('grw-editor-navbar-bottom')).toBeVisible(); + + // Append text + await appendTextToEditorUntilContains(page, page1Body); + + // Save page + await page.getByTestId('save-page-btn').click(); + + await expect(page.locator('.main')).toContainText(page1Body); + + // Duplicate page1 + await page.getByTestId('grw-contextual-sub-nav').getByTestId('open-page-item-control-btn').click(); + await page.getByTestId('open-page-duplicate-modal-btn').click(); + await expect(page.getByTestId('page-duplicate-modal')).toBeVisible(); + await page.locator('.form-control').fill(page2Path); + await page.getByTestId('btn-duplicate').click(); + + // Open Editor (page2) + await page.getByTestId('editor-button').click(); + await expect(page.getByTestId('grw-editor-navbar-bottom')).toBeVisible(); + + // Expect to see the text from which you are duplicating + await expect(page.getByTestId('page-editor-preview-body')).toContainText(page1Body); + + // Append text + await appendTextToEditorUntilContains(page, page1Body + page2Body); + + + await page.goto(page1Path); + + // Open Editor (page1) + await page.getByTestId('editor-button').click(); + await expect(page.getByTestId('grw-editor-navbar-bottom')).toBeVisible(); + + await expect(page.getByTestId('page-editor-preview-body')).toContainText(page1Body); + +}); diff --git a/apps/app/src/client/components/ReactMarkdownComponents/RichAttachment.tsx b/apps/app/src/client/components/ReactMarkdownComponents/RichAttachment.tsx index 94ecf9f57e3..a939b1bfa67 100644 --- a/apps/app/src/client/components/ReactMarkdownComponents/RichAttachment.tsx +++ b/apps/app/src/client/components/ReactMarkdownComponents/RichAttachment.tsx @@ -53,7 +53,7 @@ export const RichAttachment = React.memo((props: RichAttachmentProps) => { } return ( - <div className={`${styles.attachment} d-inline-block`}> + <div data-testid="rich-attachment" className={`${styles.attachment} d-inline-block`}> <div className="my-2 p-2 card"> <div className="p-1 card-body d-flex align-items-center"> <div className="me-2 px-0 d-flex align-items-center justify-content-center"> diff --git a/apps/app/src/components/PageView/PageAlerts/PageGrantAlert.tsx b/apps/app/src/components/PageView/PageAlerts/PageGrantAlert.tsx index e6943ee6a84..8436a7a972b 100644 --- a/apps/app/src/components/PageView/PageAlerts/PageGrantAlert.tsx +++ b/apps/app/src/components/PageView/PageAlerts/PageGrantAlert.tsx @@ -55,7 +55,7 @@ export const PageGrantAlert = (): JSX.Element => { return ( - <p className="alert alert-primary py-3 px-4"> + <p data-testid="page-grant-alert" className="alert alert-primary py-3 px-4"> {renderAlertContent()} </p> ); diff --git a/apps/app/test/cypress/e2e/23-editor/23-editor--with-navigation.cy.ts b/apps/app/test/cypress/e2e/23-editor/23-editor--with-navigation.cy.ts deleted file mode 100644 index ffdbf915a2e..00000000000 --- a/apps/app/test/cypress/e2e/23-editor/23-editor--with-navigation.cy.ts +++ /dev/null @@ -1,175 +0,0 @@ -import path from 'path-browserify'; - -function openEditor() { - cy.get('#grw-page-editor-mode-manager').as('pageEditorModeManager').should('be.visible'); - cy.getByTestid('editor-button').click(); - cy.getByTestid('grw-editor-navbar-bottom').should('be.visible'); - cy.get('.cm-content').should('be.visible'); -} - -context('Editor while uploading to a new page', () => { - - const ssPrefix = 'editor-while-uploading-'; - - beforeEach(() => { - // login - cy.fixture("user-admin.json").then(user => { - cy.login(user.username, user.password); - }); - }); - - /** - * for the issues: - * @see https://redmine.weseek.co.jp/issues/122040 - * @see https://redmine.weseek.co.jp/issues/124281 - */ - it('should not be cleared and should prevent GrantSelector from modified', { scrollBehavior: false }, () => { - cy.visit('/Sandbox/for-122040'); - - openEditor(); - - cy.screenshot(`${ssPrefix}-prevent-grantselector-modified-1`); - - // input the body - const body = 'Hello World!'; - cy.get('.cm-content').should('be.visible').type(body, { force: true }); - cy.getByTestid('page-editor-preview-body').should('contain.text', body); - - // open GrantSelector - cy.waitUntil(() => { - // do - cy.getByTestid('grw-grant-selector').within(() => { - cy.get('button.dropdown-toggle').click({force: true}); - }); - // wait until - return cy.getByTestid('grw-grant-selector-dropdown-menu').then($elem => $elem.is(':visible')) - }); - - // Select "Only me" - cy.getByTestid('grw-grant-selector-dropdown-menu').find('.dropdown-item').should('have.length', 4).then((menuItems) => { - // click "Only me" - menuItems[2].click(); - }) - - cy.getByTestid('grw-grant-selector').find('.dropdown-toggle').should('contain.text', 'Only me'); - cy.screenshot(`${ssPrefix}-prevent-grantselector-modified-2`); - - // intercept API req/res for fixing labels - const dummyAttachmentId = '64b000000000000000000000'; - let uploadedAttachmentId = ''; - cy.intercept('POST', '/_api/v3/attachment', (req) => { - req.continue((res) => { - // store the attachment id - uploadedAttachmentId = res.body.attachment._id; - // overwrite filePathProxied - res.body.attachment.filePathProxied = `/attachment/${dummyAttachmentId}`; - }); - }).as('attachmentsAdd'); - cy.intercept('GET', `/_api/v3/attachment?attachmentId=${dummyAttachmentId}`, (req) => { - // replace attachmentId query - req.url = req.url.replace(dummyAttachmentId, uploadedAttachmentId); - req.continue((res) => { - // overwrite the attachment createdAt - res.body.attachment.createdAt = new Date('2023-07-01T00:00:00'); - }); - }); - - // drag-drop a file - const filePath = path.relative('/', path.resolve(Cypress.spec.relative, '../assets/example.txt')); - cy.get('.dropzone').eq(0).selectFile(filePath, { action: 'drag-drop' }); - cy.wait('@attachmentsAdd'); - - cy.screenshot(`${ssPrefix}-prevent-grantselector-modified-3`); - - // Update page using shortcut keys - cy.get('.cm-content').click({force: true}).type('{ctrl+s}'); - - cy.screenshot(`${ssPrefix}-prevent-grantselector-modified-4`); - - // expect - cy.get('.Toastify__toast').should('contain.text', 'Saved successfully'); - cy.get('.cm-content').should('contain.text', body); - cy.get('.cm-content').should('contain.text', '[example.txt](/attachment/64b000000000000000000000'); - cy.getByTestid('grw-grant-selector').find('.dropdown-toggle').should('contain.text', 'Only me'); - cy.screenshot(`${ssPrefix}-prevent-grantselector-modified-5`); - }); - -}); - -context('Editor while navigation', () => { - - const ssPrefix = 'editor-while-navigation-'; - - beforeEach(() => { - // login - cy.fixture("user-admin.json").then(user => { - cy.login(user.username, user.password); - }); - }); - - /** - * for the issue: - * @see https://redmine.weseek.co.jp/issues/115285 - */ - it('Successfully updating the page body', { scrollBehavior: false }, () => { - const page1Path = '/Sandbox/for-115285/page1'; - const page2Path = '/Sandbox/for-115285/page2'; - - cy.visit(page1Path); - - openEditor(); - - // page1 - const bodyHello = 'hello'; - cy.get('.cm-content').should('be.visible').type(bodyHello, { force: true }); - cy.getByTestid('page-editor-preview-body').should('contain.text', bodyHello); - cy.get('.cm-content').screenshot(`${ssPrefix}-editor-for-page1`); - - // save page1 - cy.getByTestid('save-page-btn').click(); - - // open duplicate modal - cy.waitUntil(() => { - // do - cy.getByTestid('grw-contextual-sub-nav').within(() => { - cy.getByTestid('open-page-item-control-btn').find('button').click({force: true}); - }); - // wait until - return cy.getByTestid('page-item-control-menu').then($elem => $elem.is(':visible')) - }); - cy.getByTestid('open-page-duplicate-modal-btn').filter(':visible').click({force: true}); - - // duplicate and navigate to page1 - cy.getByTestid('page-duplicate-modal').should('be.visible').within(() => { - cy.get('input.form-control').clear(); - cy.get('input.form-control').type(page2Path); - cy.getByTestid('btn-duplicate').click(); - }) - - openEditor(); - cy.get('.cm-content').screenshot(`${ssPrefix}-editor-for-page2`); - - // type (without save) - const bodyWorld = ' world!!' - cy.get('.cm-content').should('be.visible').type(`{moveToEnd}${bodyWorld}`, { force: true }); - cy.getByTestid('page-editor-preview-body').should('contain.text', `${bodyHello}${bodyWorld}`); - cy.get('.cm-content').screenshot(`${ssPrefix}-editor-for-page2-modified`); - - // create a link to page1 - cy.get('.cm-content').type('\n\n[page1](./page1)'); - - // go to page1 - cy.getByTestid('page-editor-preview-body').within(() => { - cy.get("a:contains('page1')").click(); - }); - - openEditor(); - - cy.get('.cm-content').screenshot(`${ssPrefix}-editor-for-page1-returned`); - - // expect - cy.get('.cm-content').should('contain.text', bodyHello); - cy.get('.cm-content').should('not.contain.text', bodyWorld); // text that added to page2 - cy.get('.cm-content').should('not.contain.text', 'page1'); // text that added to page2 - }); -});