Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace isomorphic jest mocks with msw handlers #944

Merged
merged 14 commits into from
Jan 30, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export default function useCustomer() {
}

const response = await api.shopperCustomers.registerCustomer({body})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

// Check for error json response
if (response.detail && response.title && response.type) {
throw new Error(response.detail)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,15 @@ import Suggestions from './partials/suggestions'
import {noop} from '../../utils/utils'
import mockSearchResults from '../../commerce-api/mocks/searchResults'
import mockConfig from '../../../config/mocks/default'

jest.mock('commerce-sdk-isomorphic', () => {
const sdk = jest.requireActual('commerce-sdk-isomorphic')
return {
...sdk,
ShopperSearch: class ShopperSearchMock extends sdk.ShopperSearch {
async getSearchSuggestions() {
return mockSearchResults
}
}
}
})
import {rest} from 'msw'

beforeEach(() => {
jest.resetModules()
global.server.use(
rest.get('*/search-suggestions', (req, res, ctx) => {
return res(ctx.delay(0), ctx.status(200), ctx.json(mockSearchResults))
})
)
})

test('renders SearchInput', () => {
Expand Down
118 changes: 40 additions & 78 deletions packages/template-retail-react-app/app/hooks/use-auth-modal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ import {renderWithProviders, createPathWithDefaults} from '../utils/test-utils'
import {AuthModal, useAuthModal} from './use-auth-modal'
import {BrowserRouter as Router, Route} from 'react-router-dom'
import Account from '../pages/account'
import {rest} from 'msw'

jest.mock('../commerce-api/einstein')

const mockPasswordToken = {
email: '[email protected]',
expiresInMinutes: 10,
login: '[email protected]',
resetToken: 'testresettoken'
}

const mockRegisteredCustomer = {
authType: 'registered',
customerId: 'registeredCustomerId',
Expand All @@ -26,75 +34,15 @@ const mockRegisteredCustomer = {
}

const mockLogin = jest.fn()
jest.useFakeTimers()

jest.mock('../commerce-api/auth', () => {
return jest.fn().mockImplementation(() => {
return {
login: mockLogin.mockImplementation(async () => {
throw new Error('invalid credentials')
}),
getLoggedInToken: jest.fn().mockImplementation(async () => {
return {customer_id: 'mockcustomerid'}
})
login: mockLogin
}
})
})

jest.mock('commerce-sdk-isomorphic', () => {
const sdk = jest.requireActual('commerce-sdk-isomorphic')
return {
...sdk,
ShopperLogin: class ShopperLoginMock extends sdk.ShopperLogin {
async getAccessToken() {
return {
access_token: 'accesstoken',
refresh_token: 'refreshtoken',
customer_id: 'customerId'
}
}
authenticateCustomer() {
return {url: '/callback'}
}
},
ShopperCustomers: class ShopperCustomersMock extends sdk.ShopperCustomers {
async registerCustomer() {
return mockRegisteredCustomer
}
async getCustomer(args) {
if (args.parameters.customerId === 'customerid') {
return {
authType: 'guest',
customerId: 'customerid'
}
}
return mockRegisteredCustomer
}
async authorizeCustomer() {
return {
headers: {
get(key) {
return {authorization: 'guestToken'}[key]
}
},
json: async () => ({
authType: 'guest',
customerId: 'customerid'
})
}
}
async getResetPasswordToken() {
return {
email: '[email protected]',
expiresInMinutes: 10,
login: '[email protected]',
resetToken: 'testresettoken'
}
}
}
}
})

jest.mock('../commerce-api/utils', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to remove this?

const originalModule = jest.requireActual('../commerce-api/utils')
return {
Expand Down Expand Up @@ -141,13 +89,21 @@ MockedComponent.propTypes = {
// Set up and clean up
beforeEach(() => {
authModal = undefined
jest.useFakeTimers()
global.server.use(
rest.post('*/customers', (req, res, ctx) => {
return res(ctx.delay(0), ctx.status(200), ctx.json(mockRegisteredCustomer))
}),
rest.get('*/customers/:customerId', (req, res, ctx) => {
return res(ctx.delay(0), ctx.status(200), ctx.json(mockRegisteredCustomer))
}),
rest.post('*/customers/password/actions/create-reset-token', (req, res, ctx) => {
return res(ctx.delay(0), ctx.status(200), ctx.json(mockPasswordToken))
})
)
})
afterEach(() => {
localStorage.clear()
jest.resetModules()
jest.runOnlyPendingTimers()
jest.useRealTimers()
})

test('Renders login modal by default', async () => {
Expand All @@ -166,9 +122,8 @@ test('Renders login modal by default', async () => {

test('Allows customer to sign in to their account', async () => {
mockLogin.mockImplementationOnce(async () => {
return {url: '/callback'}
return {url: '/callback', customerId: 'registeredCustomerId'}
})

// render our test component
renderWithProviders(<MockedComponent />)

Expand All @@ -180,6 +135,7 @@ test('Allows customer to sign in to their account', async () => {
user.type(screen.getByLabelText('Email'), '[email protected]')
user.type(screen.getByLabelText('Password'), 'Password!1')
user.click(screen.getByText(/sign in/i))

// wait for successful toast to appear
await waitFor(() => {
expect(screen.getByText(/Welcome Tester/i)).toBeInTheDocument()
Expand All @@ -188,6 +144,10 @@ test('Allows customer to sign in to their account', async () => {
})

test('Renders error when given incorrect log in credentials', async () => {
mockLogin.mockImplementationOnce(async () => {
throw new Error('invalid credentials')
})

// render our test component
renderWithProviders(<MockedComponent />)

Expand All @@ -208,22 +168,23 @@ test('Renders error when given incorrect log in credentials', async () => {

test('Allows customer to generate password token', async () => {
// render our test component
renderWithProviders(<MockedComponent />)
renderWithProviders(<MockedComponent initialView="password" />)

// open the modal
const trigger = screen.getByText(/open modal/i)
user.click(trigger)

// switch to 'reset password' view
user.click(screen.getByText(/forgot password/i))
expect(authModal.isOpen).toBe(true)

// enter credentials and submit
user.type(screen.getByLabelText('Email'), '[email protected]')
user.click(within(screen.getByTestId('sf-auth-modal-form')).getByText(/reset password/i))
const withinForm = within(screen.getByTestId('sf-auth-modal-form'))
user.type(withinForm.getByLabelText('Email'), '[email protected]')
user.click(withinForm.getByText(/reset password/i))

// wait for success state
expect(await screen.findByText(/password reset/i)).toBeInTheDocument()
expect(screen.getByText(/[email protected]/i)).toBeInTheDocument()
await waitFor(() => {
expect(screen.getByText(/password reset/i)).toBeInTheDocument()
expect(screen.getByText(/[email protected]/i)).toBeInTheDocument()
})
})

test('Allows customer to open generate password token modal from everywhere', () => {
Expand All @@ -248,10 +209,10 @@ test('Allows customer to open generate password token modal from everywhere', ()
})

test('Allows customer to create an account', async () => {
jest.setTimeout(30000)
mockLogin.mockImplementationOnce(async () => {
return {url: '/callback'}
return {url: '/callback', customerId: 'registeredCustomerId'}
})

// render our test component
renderWithProviders(<MockedComponent />)

Expand All @@ -272,6 +233,7 @@ test('Allows customer to create an account', async () => {
user.paste(withinForm.getAllByLabelText(/password/i)[0], 'Password!1')
user.click(withinForm.getByText(/create account/i))

// wait for redirecting to account page
expect(await screen.findByText(/welcome tester/i, {}, {timeout: 30000})).toBeInTheDocument()
await waitFor(() => {
expect(screen.getAllByText(/welcome tester/i).length).toEqual(2)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,23 @@ import {useProductViewModal} from './use-product-view-modal'
import {DEFAULT_LOCALE} from '../utils/test-utils'
import {renderWithProviders} from '../utils/test-utils'
import messages from '../translations/compiled/en-GB.json'
import {rest} from 'msw'

const mockProduct = {
...mockProductDetail,
id: '750518699660M',
variationValues: {
color: 'BLACKFB',
size: '050',
width: 'V'
},
c_color: 'BLACKFB',
c_isNew: true,
c_refinementColor: 'black',
c_size: '050',
c_width: 'V'
}

jest.mock('commerce-sdk-isomorphic', () => {
const sdk = jest.requireActual('commerce-sdk-isomorphic')
return {
...sdk,
ShopperProducts: class ShopperProductsMock extends sdk.ShopperProducts {
async getProduct() {
return {
...mockProductDetail,
id: '750518699660M',
variationValues: {
color: 'BLACKFB',
size: '050',
width: 'V'
},
c_color: 'BLACKFB',
c_isNew: true,
c_refinementColor: 'black',
c_size: '050',
c_width: 'V'
}
}
}
}
})
const MockComponent = ({product}) => {
const productViewModalData = useProductViewModal(product)
const [isShown, setIsShown] = React.useState(false)
Expand All @@ -64,6 +56,14 @@ MockComponent.propTypes = {
product: PropTypes.object
}

beforeEach(() => {
global.server.use(
rest.get('*/products/:productId', (req, res, ctx) => {
return res(ctx.delay(0), ctx.json(mockProduct))
})
)
})

describe('useProductViewModal hook', () => {
test('return proper data', () => {
const history = createMemoryHistory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,6 @@ let mockCustomer = {}

jest.setTimeout(30000)

jest.mock('commerce-sdk-isomorphic', () => {
const sdk = jest.requireActual('commerce-sdk-isomorphic')
return {
...sdk,
ShopperCustomers: class ShopperCustomersMock extends sdk.ShopperCustomers {
async createCustomerAddress(address) {
mockCustomer.addresses = [address.body]
return {}
}

async updateCustomerAddress(address) {
mockCustomer.addresses[0] = address.body
return {}
}

async removeCustomerAddress() {
mockCustomer.addresses = undefined
return {}
}
}
}
})

const mockToastSpy = jest.fn()
jest.mock('@chakra-ui/toast', () => {
return {
Expand Down Expand Up @@ -71,17 +48,29 @@ beforeEach(() => {
lastName: 'Keane',
login: '[email protected]'
}
global.server.use(
rest.get('*/customers/:customerId', (req, res, ctx) => {
return res(ctx.delay(0), ctx.json(mockCustomer))
}),
rest.post('*/customers/:customerId/addresses', (req, res, ctx) => {
mockCustomer.addresses = [req.body]
return res(ctx.delay(0), ctx.status(200), ctx.json(req.body))
}),
rest.patch('*/customers/:customerId/addresses/:addressName', (req, res, ctx) => {
mockCustomer.addresses[0] = req.body
return res(ctx.delay(0), ctx.status(200), ctx.json(req.body))
}),
rest.delete('*/customers/:customerId/addresses/:addressName', (req, res, ctx) => {
mockCustomer.addresses = undefined
return res(ctx.delay(0), ctx.status(200))
})
)
})
afterEach(() => {
localStorage.clear()
})

test('Allows customer to add/edit/remove addresses', async () => {
global.server.use(
rest.get('*/customers/:customerId', (req, res, ctx) => {
return res(ctx.delay(0), ctx.json(mockCustomer))
})
)
renderWithProviders(<MockedComponent />)
await waitFor(() => expect(screen.getByText('registeredCustomerId')).toBeInTheDocument())

Expand Down
Loading