diff --git a/.changeset/orange-waves-dance.md b/.changeset/orange-waves-dance.md new file mode 100644 index 0000000000..2356972c48 --- /dev/null +++ b/.changeset/orange-waves-dance.md @@ -0,0 +1,6 @@ +--- +'@commercetools-frontend/application-shell': patch +'@commercetools-frontend/cypress': patch +--- + +Introduce end-to-end tests to validate custom views templates diff --git a/cypress/e2e/template-starter/channels.cy.ts b/cypress/e2e/custom-application-template-starter/channels.cy.ts similarity index 100% rename from cypress/e2e/template-starter/channels.cy.ts rename to cypress/e2e/custom-application-template-starter/channels.cy.ts diff --git a/cypress/e2e/template-starter/welcome.cy.ts b/cypress/e2e/custom-application-template-starter/welcome.cy.ts similarity index 100% rename from cypress/e2e/template-starter/welcome.cy.ts rename to cypress/e2e/custom-application-template-starter/welcome.cy.ts diff --git a/cypress/e2e/custom-view-template-starter/channels.cy.ts b/cypress/e2e/custom-view-template-starter/channels.cy.ts new file mode 100644 index 0000000000..2c17862988 --- /dev/null +++ b/cypress/e2e/custom-view-template-starter/channels.cy.ts @@ -0,0 +1,22 @@ +import { + ENTRY_POINT_CUSTOM_VIEW_TEMPLATE_STARTER, + URL_CUSTOM_VIEW_TEMPLATE_STARTER, +} from '../../support/urls'; + +describe('Channels', () => { + beforeEach(() => { + cy.loginToMerchantCenter({ + entryPointUriPath: ENTRY_POINT_CUSTOM_VIEW_TEMPLATE_STARTER, + initialRoute: URL_CUSTOM_VIEW_TEMPLATE_STARTER, + }); + }); + it('should render page', () => { + cy.findByText('Open the Custom View').click(); + cy.get('#custom-view-TODO') + .getIframeBody() + .within(() => { + cy.findByText('Channels list').should('exist'); + cy.findByText('Store Berlin').should('exist'); + }); + }); +}); diff --git a/cypress/e2e/custom-view-template-starter/welcome.cy.ts b/cypress/e2e/custom-view-template-starter/welcome.cy.ts new file mode 100644 index 0000000000..2e9ae24026 --- /dev/null +++ b/cypress/e2e/custom-view-template-starter/welcome.cy.ts @@ -0,0 +1,17 @@ +import { + ENTRY_POINT_CUSTOM_VIEW_TEMPLATE_STARTER, + URL_CUSTOM_VIEW_TEMPLATE_STARTER, +} from '../../support/urls'; + +describe('Welcome', () => { + beforeEach(() => { + cy.loginToMerchantCenter({ + entryPointUriPath: ENTRY_POINT_CUSTOM_VIEW_TEMPLATE_STARTER, + initialRoute: URL_CUSTOM_VIEW_TEMPLATE_STARTER, + }); + }); + it('should render page', () => { + cy.findByText('Custom View loader').should('exist'); + cy.findByText('Processing...').should('not.exist'); + }); +}); diff --git a/cypress/support/urls.ts b/cypress/support/urls.ts index ac38c8e7f2..51ec55fa67 100644 --- a/cypress/support/urls.ts +++ b/cypress/support/urls.ts @@ -1,3 +1,5 @@ +import { CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH } from '@commercetools-frontend/constants'; + export const projectKey = Cypress.env('PROJECT_KEY'); export const URL_BASE = `/${projectKey}`; @@ -11,3 +13,7 @@ export const URL_APP_KIT_PLAYGROUND_DATE_FORMATTERS = `${URL_APP_KIT_PLAYGROUND} export const ENTRY_POINT_TEMPLATE_STARTER = 'template-starter'; export const URL_TEMPLATE_STARTER = `${URL_BASE}/${ENTRY_POINT_TEMPLATE_STARTER}`; export const URL_TEMPLATE_STARTER_CHANNELS = `${URL_TEMPLATE_STARTER}/channels`; + +export const ENTRY_POINT_CUSTOM_VIEW_TEMPLATE_STARTER = + CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH; +export const URL_CUSTOM_VIEW_TEMPLATE_STARTER = `${URL_BASE}/${CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH}`; diff --git a/package.json b/package.json index cc779c1cd8..3e79fc7023 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "test:visual": "jest --config jest.visual.config.js --runInBand --testTimeout 10000", "test:e2e": "cypress run", "test:e2e:playground": "cypress run --spec 'cypress/e2e/playground/**/*.cy.ts'", - "test:e2e:template-custom-application-starter": "cypress run --spec 'cypress/e2e/template-starter/**/*.cy.ts'", - "test:e2e:template-custom-view-starter": "echo \"No tests implemented yet\"", + "test:e2e:template-custom-application-starter": "cypress run --spec 'cypress/e2e/custom-application-template-starter/**/*.cy.ts'", + "test:e2e:template-custom-view-starter": "cypress run --spec 'cypress/e2e/custom-view-template-starter/**/*.cy.ts'", "vrt:components": "percy exec -- pnpm test:visual", "playground:build": "pnpm --filter @commercetools-local/playground run build", "playground:start": "pnpm --filter @commercetools-local/playground run start", diff --git a/packages/application-shell/src/components/custom-view-shell/custom-view-shell.tsx b/packages/application-shell/src/components/custom-view-shell/custom-view-shell.tsx index 3e5bdfa688..32cd48c364 100644 --- a/packages/application-shell/src/components/custom-view-shell/custom-view-shell.tsx +++ b/packages/application-shell/src/components/custom-view-shell/custom-view-shell.tsx @@ -101,6 +101,14 @@ function StrictModeEnablement(props: TStrictModeEnablementProps) { } } +/* + During e2e tests, the Custom View template is built in production mode but still runs on localhost. + Checking for local production mode is necessary for applying the development host URL, + creating an environment for testing interaction with the Custom View template. +*/ +const isLocalProdMode = + process.env.NODE_ENV === 'production' && window.app.env === 'development'; + function CustomViewShell(props: TCustomViewShellProps) { const [hostContext, setHostContext] = useState(); const iFrameCommunicationPort = useRef(); @@ -171,7 +179,7 @@ function CustomViewShell(props: TCustomViewShellProps) { } const hostUrl = - process.env.NODE_ENV === 'development' + process.env.NODE_ENV === 'development' || isLocalProdMode ? window.app.__DEVELOPMENT__?.customViewHostUrl! : hostContext.hostUrl; @@ -232,7 +240,10 @@ function CustomViewShell(props: TCustomViewShellProps) { } const CustomViewShellWrapper = (props: TCustomViewShellProps) => { - if (process.env.NODE_ENV === 'development' && !props.disableDevHost) { + if ( + (process.env.NODE_ENV === 'development' || isLocalProdMode) && + !props.disableDevHost + ) { return ( }> diff --git a/packages/cypress/add-commands/index.d.ts b/packages/cypress/add-commands/index.d.ts index 16e028961a..e339fe88e8 100644 --- a/packages/cypress/add-commands/index.d.ts +++ b/packages/cypress/add-commands/index.d.ts @@ -45,5 +45,13 @@ declare namespace Cypress { // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#import-types menuItemTextMatcher: import('./dist/commercetools-frontend-cypress-add-commands.cjs').Matcher ): Chainable; + + /** + * Returns the body of the chained iframe element + * + * @example + * cy.get('#iframe-id').getIframeBody() + */ + getIframeBody(): Chainable; } } diff --git a/packages/cypress/src/add-commands/index.ts b/packages/cypress/src/add-commands/index.ts index 3e9d587c9d..2d9bf447a0 100644 --- a/packages/cypress/src/add-commands/index.ts +++ b/packages/cypress/src/add-commands/index.ts @@ -50,3 +50,16 @@ Cypress.Commands.add( .hover(); } ); + +// https://github.com/cypress-io/cypress/issues/136#issuecomment-342391119 +Cypress.Commands.add( + 'getIframeBody', + { prevSubject: 'element' }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ($iframe: any) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return new Cypress.Promise((resolve: any) => { + resolve($iframe.contents().find('body')); + }); + } +);