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()
})
})
})