diff --git a/.changeset/wet-plants-pretend.md b/.changeset/wet-plants-pretend.md new file mode 100644 index 000000000..8af67b650 --- /dev/null +++ b/.changeset/wet-plants-pretend.md @@ -0,0 +1,12 @@ +--- +"@frontify/app-bridge": major +--- + +BREAKING CHANGE: +Split the testing utilities out of the main bundle, so they don't end up in production builds. +You will need to update the import paths in your tests: + +```git +- import { AssetDummy, withAppBridgeBlockStubs } from '@frontify/app-bridge'; ++ import { AssetDummy, withAppBridgeBlockStubs } from '@frontify/app-bridge/testing'; +``` diff --git a/packages/app-bridge/src/index.ts b/packages/app-bridge/src/index.ts index d2022f0d7..b6752588e 100644 --- a/packages/app-bridge/src/index.ts +++ b/packages/app-bridge/src/index.ts @@ -13,6 +13,5 @@ export * from './errors'; export * from './helpers'; export * from './registries'; export * from './react'; -export * from './tests'; export * from './types'; export * from './utilities'; diff --git a/packages/app-bridge/src/react/useBrandportalLink.spec.ts b/packages/app-bridge/src/react/useBrandportalLink.spec.ts index 2e382b889..c9ef21775 100644 --- a/packages/app-bridge/src/react/useBrandportalLink.spec.ts +++ b/packages/app-bridge/src/react/useBrandportalLink.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { act, renderHook } from '@testing-library/react'; diff --git a/packages/app-bridge/src/react/useCategorizedDocumentPages.spec.ts b/packages/app-bridge/src/react/useCategorizedDocumentPages.spec.ts index e616e5295..239c7dc29 100644 --- a/packages/app-bridge/src/react/useCategorizedDocumentPages.spec.ts +++ b/packages/app-bridge/src/react/useCategorizedDocumentPages.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/app-bridge/src/react/useCoverPage.spec.ts b/packages/app-bridge/src/react/useCoverPage.spec.ts index a5342d4c8..ec41f8ce9 100644 --- a/packages/app-bridge/src/react/useCoverPage.spec.ts +++ b/packages/app-bridge/src/react/useCoverPage.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { act, renderHook, waitFor } from '@testing-library/react'; diff --git a/packages/app-bridge/src/react/useDocumentCategories.spec.ts b/packages/app-bridge/src/react/useDocumentCategories.spec.ts index 082c903a1..6dc2085e9 100644 --- a/packages/app-bridge/src/react/useDocumentCategories.spec.ts +++ b/packages/app-bridge/src/react/useDocumentCategories.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/app-bridge/src/react/useDocumentGroups.spec.ts b/packages/app-bridge/src/react/useDocumentGroups.spec.ts index 06dc9e8d0..dc97c0675 100644 --- a/packages/app-bridge/src/react/useDocumentGroups.spec.ts +++ b/packages/app-bridge/src/react/useDocumentGroups.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/app-bridge/src/react/useGroupedDocuments.spec.ts b/packages/app-bridge/src/react/useGroupedDocuments.spec.ts index cc60ba557..7eb22ae3e 100644 --- a/packages/app-bridge/src/react/useGroupedDocuments.spec.ts +++ b/packages/app-bridge/src/react/useGroupedDocuments.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/app-bridge/src/react/useUncategorizedDocumentPages.spec.ts b/packages/app-bridge/src/react/useUncategorizedDocumentPages.spec.ts index b7f961c63..e0afb2a4a 100644 --- a/packages/app-bridge/src/react/useUncategorizedDocumentPages.spec.ts +++ b/packages/app-bridge/src/react/useUncategorizedDocumentPages.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/app-bridge/src/react/useUngroupedDocuments.spec.ts b/packages/app-bridge/src/react/useUngroupedDocuments.spec.ts index fe7ed1d6b..a3d54ff0c 100644 --- a/packages/app-bridge/src/react/useUngroupedDocuments.spec.ts +++ b/packages/app-bridge/src/react/useUngroupedDocuments.spec.ts @@ -1,5 +1,3 @@ -// @vitest-environment happy-dom - /* (c) Copyright Frontify Ltd., all rights reserved. */ import { afterEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/guideline-blocks-settings/package.json b/packages/guideline-blocks-settings/package.json index cbc0f2599..d0f87c766 100644 --- a/packages/guideline-blocks-settings/package.json +++ b/packages/guideline-blocks-settings/package.json @@ -28,6 +28,7 @@ "prettier": "prettier --check .", "prettier:fix": "prettier --write .", "test": "vitest run --silent", + "test:ui": "vitest --ui", "test:watch": "vitest", "typecheck": "tsc --noEmit" }, diff --git a/packages/guideline-blocks-settings/src/components/Attachments/Attachments.spec.ct.tsx b/packages/guideline-blocks-settings/src/components/Attachments/Attachments.spec.ct.tsx index 006f985ad..a9dc0efa4 100644 --- a/packages/guideline-blocks-settings/src/components/Attachments/Attachments.spec.ct.tsx +++ b/packages/guideline-blocks-settings/src/components/Attachments/Attachments.spec.ct.tsx @@ -1,10 +1,11 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { type AppBridgeBlock, AssetDummy, getAppBridgeBlockStub } from '@frontify/app-bridge'; +import { type AppBridgeBlock } from '@frontify/app-bridge'; import { mount } from 'cypress/react18'; import { Attachments as AttachmentsComponent } from './Attachments'; import { AttachmentsProps } from './types'; import { SinonStub } from 'sinon'; +import { getAppBridgeTestingPackage } from '../../tests/helpers/getAppBridgeTestingPackage'; const FlyoutButtonSelector = '[data-test-id="attachments-flyout-button"]'; const AssetInputSelector = '[data-test-id="asset-input-placeholder"]'; @@ -15,7 +16,7 @@ const MenuItemSelector = '[data-test-id="menu-item"]'; const LoadingCircleSelector = '[data-test-id="loading-circle"]'; const Attachments = ({ - appBridge = getAppBridgeBlockStub(), + appBridge, onDelete = cy.stub(), items, onReplaceWithBrowse = cy.stub(), @@ -23,7 +24,7 @@ const Attachments = ({ onSorted = cy.stub(), onBrowse = cy.stub(), onUpload = cy.stub(), -}: Partial) => { +}: Partial & { appBridge: AttachmentsProps['appBridge'] }) => { return ( { - it('renders attachments flyout if it is in edit mode', () => { +describe('Attachments', async () => { + it('renders attachments flyout if it is in edit mode', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + mount(); cy.get(FlyoutButtonSelector).should('exist'); }); - it('renders attachments flyout if it has attachments', () => { - mount(); + it('renders attachments flyout if it has attachments', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + + mount(); cy.get(FlyoutButtonSelector).should('exist'); }); - it('does not render attachments flyout if there are no attachments', () => { - mount(); + it('does not render attachments flyout if there are no attachments', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + + mount(); cy.get(FlyoutButtonSelector).should('not.exist'); }); - it('renders asset input if in edit mode', () => { + it('renders asset input if in edit mode', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + mount(); cy.get(FlyoutButtonSelector).click(); cy.get(AssetInputSelector).should('exist'); }); - it('does not render asset input if in view mode', () => { - mount(); + it('does not render asset input if in view mode', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + + mount(); cy.get(FlyoutButtonSelector).click(); cy.get(AssetInputSelector).should('not.exist'); }); - it('renders asset action buttons if in edit mode', () => { + it('renders asset action buttons if in edit mode', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + mount(); cy.get(FlyoutButtonSelector).click(); cy.get(ActionBarSelector).should('exist'); }); - it('does not render asset action buttons if in view mode', () => { - mount(); + it('does not render asset action buttons if in view mode', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + + mount(); cy.get(FlyoutButtonSelector).click(); cy.get(ActionBarSelector).should('not.exist'); }); - it('renders an attachment item for each asset', () => { - mount(); + it('renders an attachment item for each asset', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + + mount( + , + ); cy.get(FlyoutButtonSelector).click(); cy.get(AttachmentItemSelector).should('have.length', 3); }); it('renders loading circle for attachment item', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ editorState: true, }); if ((await isPre302Stub(appBridge)) && hasOpenAssetChooser(appBridge)) { - (appBridge.openAssetChooser as SinonStub) = cy.stub().callsArgWith(0, AssetDummy.with(4)); + // @ts-expect-error stubbing + appBridge.openAssetChooser = cy.stub().callsArgWith(0, AssetDummy.with(4)); } cy.clock(); @@ -129,7 +154,9 @@ describe('Attachments', () => { cy.get(LoadingCircleSelector).should('not.exist'); }); - it('renders focus ring on flyout button while tabbing and open it', () => { + it('renders focus ring on flyout button while tabbing and open it', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + mount( { - it('renders a simple block inject button', () => { + it('renders a simple block inject button', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [BlockInjectButtonWithStubs] = withAppBridgeBlockStubs(BlockInjectButton, {}); mount( @@ -25,7 +27,9 @@ describe('Block Inject Button', () => { .should('have.class', 'first:tw-rounded-tl last:tw-rounded-br', 'first:tw-rounded-bl last:tw-rounded-tr'); }); - it('renders a block inject button with Menu upload and asset', () => { + it('renders a block inject button with Menu upload and asset', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [BlockInjectButtonWithStubs] = withAppBridgeBlockStubs(BlockInjectButton, {}); mount( diff --git a/packages/guideline-blocks-settings/src/components/BlockItemWrapper/Toolbar/Toolbar.spec.tsx b/packages/guideline-blocks-settings/src/components/BlockItemWrapper/Toolbar/Toolbar.spec.tsx index 19a6ee821..52e9971a4 100644 --- a/packages/guideline-blocks-settings/src/components/BlockItemWrapper/Toolbar/Toolbar.spec.tsx +++ b/packages/guideline-blocks-settings/src/components/BlockItemWrapper/Toolbar/Toolbar.spec.tsx @@ -1,23 +1,21 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { getAppBridgeBlockStub } from '@frontify/app-bridge'; import { render } from '@testing-library/react'; import { beforeAll, describe, expect, it, vi } from 'vitest'; import { AttachmentsProvider } from '../../../hooks/useAttachments'; +import { getAppBridgeTestingPackage } from '../../../tests/helpers/getAppBridgeTestingPackage'; import { Toolbar } from './Toolbar'; -/** - * @vitest-environment happy-dom - */ - const ATTACHMENTS_FLYOUT_ID = 'attachments-flyout-content'; const MENU_FLYOUT_ID = 'menu-item'; const MOCK_ASSET_FIELD_ID = 'attachment'; -describe('Toolbar', () => { +describe('Toolbar', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + beforeAll(() => { vi.stubGlobal( 'Worker', diff --git a/packages/guideline-blocks-settings/src/components/Link/LinkInput.spec.ct.tsx b/packages/guideline-blocks-settings/src/components/Link/LinkInput.spec.ct.tsx index 3ff11a159..fa800824d 100644 --- a/packages/guideline-blocks-settings/src/components/Link/LinkInput.spec.ct.tsx +++ b/packages/guideline-blocks-settings/src/components/Link/LinkInput.spec.ct.tsx @@ -1,9 +1,9 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { withAppBridgeBlockStubs } from '@frontify/app-bridge'; import { mount } from 'cypress/react18'; import { LinkInput } from './LinkInput'; import { ButtonSize, CheckboxState } from '@frontify/fondue'; +import { getAppBridgeTestingPackage } from '../../tests/helpers/getAppBridgeTestingPackage'; const LINK_INPUT_ID = '[data-test-id="link-input"]'; const TEXT_INPUT_ID = '[data-test-id="text-input"]'; @@ -13,13 +13,17 @@ const CLEAR_ICON_ID = '[data-test-id="clear-icon"]'; const CHECKBOX_ID = '[data-test-id="checkbox-input"]'; describe('Link Input', () => { - it('renders the link input', () => { + it('renders the link input', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(LINK_INPUT_ID).should('exist'); }); - it('renders the link inpus label, placeholder and info', () => { + it('renders the link inpus label, placeholder and info', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(LINK_INPUT_ID).should('exist'); @@ -28,21 +32,27 @@ describe('Link Input', () => { cy.get(TEXT_INPUT_ID).should('have.attr', 'placeholder', 'Custom Placeholder'); }); - it('renders the link inpu with a valid url', () => { + it('renders the link inpu with a valid url', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(LINK_INPUT_ID).should('exist'); cy.get(TEXT_INPUT_ID).should('have.value', 'https://example.com'); }); - it('renders with clear icon', () => { + it('renders with clear icon', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(CLEAR_ICON_ID).should('exist'); }); - it('renders without clear icon', () => { + it('renders without clear icon', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); @@ -51,7 +61,9 @@ describe('Link Input', () => { cy.get(CLEAR_ICON_ID).should('not.exist'); }); - it('toggles checkbox on click', () => { + it('toggles checkbox on click', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount( { cy.get('@onToggleTab').should('be.called.with', true); }); - it('toggles checkbox on click if its already checked', () => { + it('toggles checkbox on click if its already checked', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); @@ -75,7 +89,9 @@ describe('Link Input', () => { cy.get('@onToggleTab').should('be.called.with', false); }); - it('handles "Checked" state from newTab', () => { + it('handles "Checked" state from newTab', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount( { cy.get('@onToggleTab').should('be.called.with', false); }); - it('handles "Unchecked" state from newTab', () => { + it('handles "Unchecked" state from newTab', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount( { cy.get('@onToggleTab').should('be.called.with', true); }); - it('types into search field', () => { + it('types into search field', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); @@ -112,28 +132,36 @@ describe('Link Input', () => { cy.get('@onUrlChange').should('be.called.with', 'https://frontify.com'); }); - it('shows internal link button', () => { + it('shows internal link button', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(BUTTON_ID).should('exist'); }); - it('hides internal link button', () => { + it('hides internal link button', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(BUTTON_ID).should('not.exist'); }); - it('renders * if input is required', () => { + it('renders * if input is required', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); cy.get(INPUT_LABEL_CONTAINER_ID).contains('*'); }); - it('renders custom buttonsize', () => { + it('renders custom buttonsize', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkInputWithStubs] = withAppBridgeBlockStubs(LinkInput, {}); mount(); diff --git a/packages/guideline-blocks-settings/src/components/Link/LinkSelector/LinkSelector.spec.ct.tsx b/packages/guideline-blocks-settings/src/components/Link/LinkSelector/LinkSelector.spec.ct.tsx index 6ab742c62..0a5564b9b 100644 --- a/packages/guideline-blocks-settings/src/components/Link/LinkSelector/LinkSelector.spec.ct.tsx +++ b/packages/guideline-blocks-settings/src/components/Link/LinkSelector/LinkSelector.spec.ct.tsx @@ -1,15 +1,8 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { - DocumentApiDummy, - DocumentPageApiDummy, - DocumentSectionApiDummy, - getAppBridgeBlockStub, - withAppBridgeBlockStubs, -} from '@frontify/app-bridge'; import { mount } from 'cypress/react18'; import { LinkSelector } from './LinkSelector'; -import type { SinonStub } from 'sinon'; +import { getAppBridgeTestingPackage } from '../../../tests/helpers/getAppBridgeTestingPackage'; const LinkSelectorSelector = '[data-test-id="internal-link-selector"]'; const LinkSelectorButtonSelector = '[data-test-id="internal-link-selector"] > button'; @@ -19,63 +12,87 @@ const DocumentTreeItemToggleSelector = '[data-test-id="tree-item-toggle"]'; const PageLinkSelector = '[data-test-id="internal-link-selector-page-link"]'; const SectionLinkSelector = '[data-test-id="internal-link-selector-section-link"]'; -const apiDocuments = [ - { ...DocumentApiDummy.with(1), permanentLink: '/1' }, - { ...DocumentApiDummy.with(2), permanentLink: '/2' }, -]; -const apiPages = [ - { ...DocumentPageApiDummy.with(1), permanentLink: '/3' }, - { ...DocumentPageApiDummy.with(2), permanentLink: '/4' }, - { ...DocumentPageApiDummy.with(3), permanentLink: '/5' }, -]; -const apiSections = [ - { ...DocumentSectionApiDummy.with(1), permanentLink: '/6' }, - { ...DocumentSectionApiDummy.with(2), permanentLink: '/7' }, - { ...DocumentSectionApiDummy.with(3), permanentLink: '/8' }, - { ...DocumentSectionApiDummy.with(4), permanentLink: '/9' }, -]; - describe('Link Selector', () => { - it('renders the link selector button', () => { + let apiDocuments: any = []; + let apiPages: any = []; + let apiSections: any = []; + + before(async () => { + const { DocumentApiDummy, DocumentPageApiDummy, DocumentSectionApiDummy } = await getAppBridgeTestingPackage(); + + apiDocuments = [ + { ...DocumentApiDummy.with(1), permanentLink: '/1' }, + { ...DocumentApiDummy.with(2), permanentLink: '/2' }, + ]; + apiPages = [ + { ...DocumentPageApiDummy.with(1), permanentLink: '/3' }, + { ...DocumentPageApiDummy.with(2), permanentLink: '/4' }, + { ...DocumentPageApiDummy.with(3), permanentLink: '/5' }, + ]; + apiSections = [ + { ...DocumentSectionApiDummy.with(1), permanentLink: '/6' }, + { ...DocumentSectionApiDummy.with(2), permanentLink: '/7' }, + { ...DocumentSectionApiDummy.with(3), permanentLink: '/8' }, + { ...DocumentSectionApiDummy.with(4), permanentLink: '/9' }, + ]; + }); + + it('renders the link selector button', async () => { + const { withAppBridgeBlockStubs } = await getAppBridgeTestingPackage(); + const [LinkSelectorWithStubs] = withAppBridgeBlockStubs(LinkSelector, {}); mount(); cy.get(LinkSelectorSelector).should('exist'); }); - it('opens the modal on button click', () => { + it('opens the modal on button click', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); const apiDocuments = [DocumentApiDummy.with(1)]; - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount(); cy.get(LinkSelectorButtonSelector).click(); cy.get(LinkSelectorModalSelector).should('exist'); }); - it('renders two documents initially', () => { + it('renders two documents initially', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount(); cy.get(LinkSelectorButtonSelector).click(); cy.get(DocumentLinkSelector).should('have.length', 2); }); - it('renders three pages on document expand', () => { + it('renders three pages on document expand', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); - (appBridge.getDocumentPagesByDocumentId as SinonStub) = cy.stub().returns(Promise.resolve(apiPages)); - (appBridge.getDocumentSectionsByDocumentPageId as SinonStub) = cy.stub().returns(Promise.resolve(apiSections)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentPagesByDocumentId = cy.stub().returns(Promise.resolve(apiPages)); + // @ts-expect-error Stubbing + appBridge.getDocumentSectionsByDocumentPageId = cy.stub().returns(Promise.resolve(apiSections)); mount(); cy.get(LinkSelectorButtonSelector).click(); @@ -83,14 +100,20 @@ describe('Link Selector', () => { cy.get(PageLinkSelector).should('have.length', 3); }); - it('renders four sections on page expand', () => { + it('renders four sections on page expand', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); - (appBridge.getDocumentPagesByDocumentId as SinonStub) = cy.stub().returns(Promise.resolve(apiPages)); - (appBridge.getDocumentSectionsByDocumentPageId as SinonStub) = cy.stub().returns(Promise.resolve(apiSections)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentPagesByDocumentId = cy.stub().returns(Promise.resolve(apiPages)); + // @ts-expect-error Stubbing + appBridge.getDocumentSectionsByDocumentPageId = cy.stub().returns(Promise.resolve(apiSections)); mount(); cy.get(LinkSelectorButtonSelector).click(); @@ -99,28 +122,40 @@ describe('Link Selector', () => { cy.get(SectionLinkSelector).should('have.length', 4); }); - it('renders the selected section immediately if it is preselected', () => { + it('renders the selected section immediately if it is preselected', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); - (appBridge.getDocumentPagesByDocumentId as SinonStub) = cy.stub().returns(Promise.resolve(apiPages)); - (appBridge.getDocumentSectionsByDocumentPageId as SinonStub) = cy.stub().returns(Promise.resolve(apiSections)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentPagesByDocumentId = cy.stub().returns(Promise.resolve(apiPages)); + // @ts-expect-error Stubbing + appBridge.getDocumentSectionsByDocumentPageId = cy.stub().returns(Promise.resolve(apiSections)); mount(); cy.get(LinkSelectorButtonSelector).click(); cy.get(SectionLinkSelector).should('have.length', 4); }); - it('renders the all section and they are shown on focus and stores if you press enter', () => { + it('renders the all section and they are shown on focus and stores if you press enter', async () => { + const { getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const appBridge = getAppBridgeBlockStub({ blockId: 1, }); - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); - (appBridge.getDocumentPagesByDocumentId as SinonStub) = cy.stub().returns(Promise.resolve(apiPages)); - (appBridge.getDocumentSectionsByDocumentPageId as SinonStub) = cy.stub().returns(Promise.resolve(apiSections)); + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); + // @ts-expect-error Stubbing + appBridge.getDocumentPagesByDocumentId = cy.stub().returns(Promise.resolve(apiPages)); + // @ts-expect-error Stubbing + appBridge.getDocumentSectionsByDocumentPageId = cy.stub().returns(Promise.resolve(apiSections)); mount(); cy.get(LinkSelectorButtonSelector).click(); diff --git a/packages/guideline-blocks-settings/src/components/RichTextEditor/RichTextEditor.spec.ct.tsx b/packages/guideline-blocks-settings/src/components/RichTextEditor/RichTextEditor.spec.ct.tsx index 3867f7169..46b242bd7 100644 --- a/packages/guideline-blocks-settings/src/components/RichTextEditor/RichTextEditor.spec.ct.tsx +++ b/packages/guideline-blocks-settings/src/components/RichTextEditor/RichTextEditor.spec.ct.tsx @@ -1,11 +1,10 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { DocumentApiDummy, getAppBridgeBlockStub } from '@frontify/app-bridge'; import { PluginComposer } from '@frontify/fondue'; import { mount } from 'cypress/react18'; -import type { SinonStub } from 'sinon'; import { ButtonPlugin, LinkPlugin, RichTextEditor, TextStyles } from '.'; import { convertToRteValue } from '../../helpers'; +import { getAppBridgeTestingPackage } from '../../tests/helpers/getAppBridgeTestingPackage'; const RteHtmlSelector = '[data-test-id="rte-content-html"]'; const RichTextSelector = '[data-test-id="rich-text-editor"]'; @@ -17,13 +16,7 @@ const FloatingLinkModalSelector = '[data-test-id="floating-link-insert"]'; const FloatingButtonModalSelector = '[data-test-id="floating-button-insert"]'; const UrlInputSelector = 'input[id="url"]'; -const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; - -const appBridge = getAppBridgeBlockStub({ - blockId: 1, -}); - -describe('RichTextEditor', () => { +describe('RichTextEditor', async () => { it('should render a rich text editor in edit mode', () => { mount(); cy.get(RichTextSelector).should('exist'); @@ -54,9 +47,18 @@ describe('RichTextEditor', () => { cy.get(RteHtmlSelector).should('not.exist'); }); - it('should be able to select internal link', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should be able to select internal link', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { linkTag.should('have.attr', 'target', '_self'); }); - it('should be able to select internal link with target blank', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should be able to select internal link with target blank', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { linkTag.should('have.attr', 'target', '_blank'); }); - it('should prepend the URL with https:// if not exists', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should prepend the URL with https:// if not exists', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a[href="https://frontify.com"]').should('exist'); }); - it('should allow URLs that start with /document/', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should allow URLs that start with /document/', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a[href="/document/test"]').should('exist'); }); - it('should not add https:// to the URL for mailto: links', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should not add https:// to the URL for mailto: links', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a[href="mailto:info@frontify.com"]').should('exist'); }); - it('should create a link with a link typed in the RTE', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should create a link with a link typed in the RTE', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a[href="mailto:info@frontify.com"]').should('exist'); }); - it('should not create a link with a : after a word', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should not create a link with a : after a word', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a').should('not.exist'); }); - it('should allow URLs that start with /document/', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should allow URLs that start with /document/', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { cy.get(RichTextSelector).find('a[href="/document/test"]').should('exist'); }); - it('should be able to select internal button link', () => { - (appBridge.getDocumentGroups as SinonStub) = cy.stub().returns([]); - (appBridge.getAllDocuments as SinonStub) = cy.stub().returns(Promise.resolve(apiDocuments)); + it('should be able to select internal button link', async () => { + const { DocumentApiDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + const apiDocuments = [{ ...DocumentApiDummy.with(1), permanentLink: '/r/document' }]; + + const appBridge = getAppBridgeBlockStub({ + blockId: 1, + }); + + // @ts-expect-error Stubbing + appBridge.getDocumentGroups = cy.stub().returns([]); + // @ts-expect-error Stubbing + appBridge.getAllDocuments = cy.stub().returns(Promise.resolve(apiDocuments)); mount( { const initialCoordinates = { x: 0, y: 0 }; const context = { diff --git a/packages/guideline-blocks-settings/src/hooks/useAttachments.spec.tsx b/packages/guideline-blocks-settings/src/hooks/useAttachments.spec.tsx index ddf5c1851..08a3201ba 100644 --- a/packages/guideline-blocks-settings/src/hooks/useAttachments.spec.tsx +++ b/packages/guideline-blocks-settings/src/hooks/useAttachments.spec.tsx @@ -1,14 +1,16 @@ /* (c) Copyright Frontify Ltd., all rights reserved. */ -import { AssetDummy, getAppBridgeBlockStub } from '@frontify/app-bridge'; import { render, renderHook, waitFor } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; import { AttachmentsProvider, useAttachments, useAttachmentsContext, withAttachmentsProvider } from './useAttachments'; +import { getAppBridgeTestingPackage } from '../tests/helpers/getAppBridgeTestingPackage'; const MOCK_SETTINGS_ID = 'attachments'; describe('useAttachments', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + it('should have 1 attachment if attachment is added', async () => { const STUB_WITH_NO_ASSETS = getAppBridgeBlockStub({ blockId: 1, @@ -74,7 +76,9 @@ describe('useAttachments', async () => { }); }); -describe('useAttachmentsContext', () => { +describe('useAttachmentsContext', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + it('should throw an error when not a child of a provider', async () => { expect(() => renderHook(() => useAttachmentsContext())).toThrowError(); }); @@ -99,7 +103,9 @@ describe('useAttachmentsContext', () => { }); }); -describe('withAttachmentsProvider', () => { +describe('withAttachmentsProvider', async () => { + const { AssetDummy, getAppBridgeBlockStub } = await getAppBridgeTestingPackage(); + it('should provide correct info to context consumer', async () => { const STUB_WITH_THREE_ASSETS = getAppBridgeBlockStub({ blockId: 2, diff --git a/packages/guideline-blocks-settings/src/hooks/useDndSensors.spec.ts b/packages/guideline-blocks-settings/src/hooks/useDndSensors.spec.ts index e82aca097..e29d7d6b9 100644 --- a/packages/guideline-blocks-settings/src/hooks/useDndSensors.spec.ts +++ b/packages/guideline-blocks-settings/src/hooks/useDndSensors.spec.ts @@ -5,9 +5,6 @@ import { useDndSensors } from './useDndSensors'; import { describe, expect, it } from 'vitest'; import { KeyboardSensorOptions } from '@dnd-kit/core'; -/** - * @vitest-environment happy-dom - */ describe('useDndSensors', () => { it('should create a PointerSensor and a KeyboardSensor with a coordinate getter function and custom keyboardCodes', () => { const { result } = renderHook(() => useDndSensors()); diff --git a/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.spec.ts b/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.spec.ts new file mode 100644 index 000000000..2bcf6fab1 --- /dev/null +++ b/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.spec.ts @@ -0,0 +1,14 @@ +/* (c) Copyright Frontify Ltd., all rights reserved. */ + +import { describe, expect, it } from 'vitest'; + +import { getAppBridgeTestingPackage } from './getAppBridgeTestingPackage'; + +describe('getAppBridgeTestingPackage', () => { + it('returns correctly the package', async () => { + const appBridgeTestingPackage = await getAppBridgeTestingPackage(); + + expect(Object.keys(appBridgeTestingPackage).length).toBeGreaterThanOrEqual(10); + expect(appBridgeTestingPackage.getAppBridgeBlockStub).toBeDefined(); + }); +}); diff --git a/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.ts b/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.ts new file mode 100644 index 000000000..7a7caa994 --- /dev/null +++ b/packages/guideline-blocks-settings/src/tests/helpers/getAppBridgeTestingPackage.ts @@ -0,0 +1,45 @@ +/* (c) Copyright Frontify Ltd., all rights reserved. */ + +// TODO: Remove when app-bridge v3 peer deps is gone +/* eslint-disable @typescript-eslint/ban-ts-comment */ + +import packageJson from '../../../node_modules/@frontify/app-bridge/package.json'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type GetMajorVersion = T extends `${infer Major}.${infer _}` ? Major : never; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type GetMinorVersion = T extends `${infer _}.${infer Minor}.${infer _}` ? Minor : never; + +// @ts-ignore will fail if ; +type AppBridgeMinorVersion = GetMinorVersion; + +export const getAppBridgeTestingPackage = async (): AppBridgeMajorVersion extends '3' + ? AppBridgeMinorVersion extends '0' + ? Promise + : // @ts-ignore will fail if + : // @ts-ignore will fail if => { + const isAppBridgeVersionNotWithTestingExport = appBridgeVersion.startsWith('3.0.'); + + if (isAppBridgeVersionNotWithTestingExport) { + const appBridgePackage = await import('@frontify/app-bridge'); + + return appBridgePackage as typeof import('@frontify/app-bridge'); + } + + // Needed if '@frontify/app-bridge/testing'; + // @ts-ignore will fail if { const data = [ { value: 'http://www.frontify.com', expected: true },