import { render, screen, within } from '@testing-library/react' import { userEvent } from '@testing-library/user-event' import React from 'react' import SetUpSteps from '../SetUpSteps' import { SetUpProgress } from '../useSetUpProgress' import { ActivationKeyFormProps } from '../ActivationKeyForm' import { speak } from '@wordpress/a11y' import { AutoUpdates } from '../../model/autoUpdates' jest.mock( '@woocommerce/settings', () => ({ getAdminLink: (path: string) => `/wp-admin/${path}` }), { virtual: true } ) jest.mock('@wordpress/a11y', () => ({ speak: jest.fn() })) jest.mock('../ActivationKeyForm', () => ({ __esModule: true, default: ({ prominent, focusOnOpen, onConnected, }: ActivationKeyFormProps) => ( ), })) const mockAutoUpdates: { autoUpdates?: AutoUpdates failed: boolean turn: jest.Mock } = { failed: false, turn: jest.fn() } jest.mock('../../model/autoUpdates', () => ({ __esModule: true, default: () => mockAutoUpdates, })) const MYBRING_OPENED = 'posten-bring-checkout-mybring-opened' const SETTINGS = '/wp-admin/admin.php?page=wc-admin&path=/posten-bring-checkout/settings' const onConnected = jest.fn() const renderSteps = (progress: SetUpProgress, canConfigure = true) => render( ) const step = (title: string) => screen.getByRole('heading', { name: title }).closest('li') as HTMLElement const addWebshop = () => step('Add your webshop in Mybring') const connect = () => step('Connect the plugin to Mybring') const reviewSettings = () => step('Review your settings') const keepUpToDate = () => step('Keep the plugin up to date') const keyForm = () => screen.queryByRole('button', { name: /key form/ }) const openKeyForm = () => userEvent.click( within(connect()).getByRole('button', { name: 'Paste activation key' }) ) describe('SetUpSteps', () => { beforeEach(() => { window.localStorage.clear() jest.clearAllMocks() mockAutoUpdates.autoUpdates = undefined mockAutoUpdates.failed = false }) it('tells the merchant they need a Mybring user', () => { renderSteps('notConnected') expect( screen.getByRole('link', { name: /Register your company/ }) ).toHaveAttribute('href', 'https://www.mybring.com/signup/customer/company') }) it('starts with adding the webshop in Mybring', () => { renderSteps('notConnected') const openMybring = within(addWebshop()).getByRole('link', { name: /Open Mybring/, }) expect(openMybring).toHaveAttribute( 'href', 'https://www.mybring.com/checkout' ) expect(openMybring).toHaveAttribute('target', '_blank') expect(within(addWebshop()).getByText('To do')).toBeInTheDocument() }) it('marks the first step done once Mybring has been opened', async () => { renderSteps('notConnected') await userEvent.click( within(addWebshop()).getByRole('link', { name: /Open Mybring/ }) ) expect(within(addWebshop()).getByText('Done')).toBeInTheDocument() expect(within(connect()).getByText('To do')).toBeInTheDocument() }) it('remembers that Mybring has been opened', () => { window.localStorage.setItem(MYBRING_OPENED, 'yes') renderSteps('notConnected') expect(within(addWebshop()).getByText('Done')).toBeInTheDocument() }) it('shows where the steps outside this page are done', () => { renderSteps('notConnected') expect( within(addWebshop()).getByText('Mybring › Checkout') ).toBeInTheDocument() expect(within(connect()).queryByText('Where:')).not.toBeInTheDocument() expect( within(reviewSettings()).getByText('Posten Bring Checkout › Settings') ).toBeInTheDocument() }) describe('connecting the plugin', () => { it('keeps the key field out of the way until the merchant asks for it', () => { renderSteps('notConnected') expect(keyForm()).not.toBeInTheDocument() }) it('lets the merchant paste the key right here once asked for', async () => { renderSteps('notConnected') await openKeyForm() expect(within(connect()).getByText('key form quiet')).toBeInTheDocument() expect( within(connect()).queryByRole('button', { name: 'Paste activation key', }) ).not.toBeInTheDocument() }) it('moves focus into the key field the merchant asked for', async () => { renderSteps('notConnected') await openKeyForm() expect(keyForm()).toHaveAttribute('data-focus-on-open', 'true') }) it('leaves focus alone when the key field opens after visiting Mybring', () => { window.localStorage.setItem(MYBRING_OPENED, 'yes') renderSteps('notConnected') expect(keyForm()).toHaveAttribute('data-focus-on-open', 'false') }) it('shows the key field as the main action once Mybring has been opened', () => { window.localStorage.setItem(MYBRING_OPENED, 'yes') renderSteps('notConnected') expect( within(connect()).getByText('key form prominent') ).toBeInTheDocument() }) it('tells when the plugin has been connected', async () => { renderSteps('notConnected') await openKeyForm() await userEvent.click(keyForm()!) expect(onConnected).toHaveBeenCalled() }) it('marks the first two steps done once connected', () => { renderSteps('complete') expect(within(addWebshop()).getByText('Done')).toBeInTheDocument() expect(within(connect()).getByText('Done')).toBeInTheDocument() expect(keyForm()).not.toBeInTheDocument() }) }) describe('reviewing the settings', () => { it('leaves reviewing the settings until the plugin is connected', () => { renderSteps('notConnected') expect(within(reviewSettings()).getByText('To do')).toBeInTheDocument() expect( within(reviewSettings()).getByRole('button', { name: 'Open settings' }) ).toHaveAttribute('aria-disabled', 'true') }) it('takes the merchant to the settings once connected', () => { renderSteps('complete') const openSettings = within(reviewSettings()).getByRole('link', { name: 'Open settings', }) expect(openSettings).toHaveAttribute('href', SETTINGS) expect(openSettings).not.toHaveAttribute('aria-disabled') }) }) describe('for a user who may not configure the plugin', () => { it('asks them to have an administrator connect the plugin', () => { window.localStorage.setItem(MYBRING_OPENED, 'yes') renderSteps('notConnected', false) expect( within(connect()).getByText( 'Only an administrator can connect the plugin. Ask yours to paste the activation key from Mybring here.' ) ).toBeInTheDocument() expect(keyForm()).not.toBeInTheDocument() expect( within(connect()).queryByRole('button', { name: 'Paste activation key', }) ).not.toBeInTheDocument() }) it('asks them to have an administrator review the settings', () => { renderSteps('complete', false) expect( within(reviewSettings()).getByText( 'Ask your administrator to check that your store address is complete, and to choose whether labels print automatically and whether customers can return items with Posten.' ) ).toBeInTheDocument() expect( within(reviewSettings()).queryByRole('link', { name: 'Open settings' }) ).not.toBeInTheDocument() }) }) describe('once the plugin is connected during the visit', () => { const connectDuringVisit = () => { const { rerender } = renderSteps('notConnected') rerender( ) } it('moves focus to the next step, as the key field is gone', () => { connectDuringVisit() expect( within(reviewSettings()).getByRole('link', { name: 'Open settings' }) ).toHaveFocus() }) it('tells screen reader users the plugin is connected and what comes next', () => { connectDuringVisit() expect(speak).toHaveBeenCalledWith( 'The plugin is connected. Next, review your settings.', 'polite' ) }) it('leaves focus alone when the plugin was connected on arrival', () => { renderSteps('complete') expect( within(reviewSettings()).getByRole('link', { name: 'Open settings' }) ).not.toHaveFocus() expect(speak).not.toHaveBeenCalled() }) }) describe('automatic updates', () => { it('offers to turn them on to those who can', async () => { mockAutoUpdates.autoUpdates = { enabled: false, canChange: true } renderSteps('notConnected') expect(within(keepUpToDate()).getByText('To do')).toBeInTheDocument() await userEvent.click( within(keepUpToDate()).getByRole('button', { name: 'Turn on automatic updates', }) ) expect(mockAutoUpdates.turn).toHaveBeenCalledWith(true) }) it('marks the step done once they are on', () => { mockAutoUpdates.autoUpdates = { enabled: true, canChange: false } renderSteps('notConnected') expect(within(keepUpToDate()).getByText('Done')).toBeInTheDocument() expect( within(keepUpToDate()).queryByRole('button') ).not.toBeInTheDocument() }) it('leaves the step out for those who cannot turn them on', () => { mockAutoUpdates.autoUpdates = { enabled: false, canChange: false } renderSteps('notConnected') expect( screen.queryByRole('heading', { name: 'Keep the plugin up to date' }) ).not.toBeInTheDocument() }) it('leaves the step out until the status is known', () => { renderSteps('notConnected') expect( screen.queryByRole('heading', { name: 'Keep the plugin up to date' }) ).not.toBeInTheDocument() }) it('says so when they could not be turned on', () => { mockAutoUpdates.autoUpdates = { enabled: false, canChange: true } mockAutoUpdates.failed = true renderSteps('notConnected') expect( within(keepUpToDate()).getByText( 'Automatic updates could not be turned on. Please try again.' ) ).toBeInTheDocument() }) }) })