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

361 fix home specs #373

Merged
merged 11 commits into from
Feb 14, 2024
12 changes: 9 additions & 3 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ module.exports = defineConfig({
env: {
TEST_SCIENTIST_USER: '[email protected]',
TEST_SCIENTIST_PW: '!test1234',
NEXT_PUBLIC_PROVIDER_NAME: 'acme',
NEXT_PUBLIC_PROVIDER_ID: '572'
NEXT_PUBLIC_PROVIDER_NAME: process.env.NEXT_PUBLIC_PROVIDER_NAME,
NEXT_PUBLIC_PROVIDER_ID: process.env.NEXT_PUBLIC_PROVIDER_ID,
NEXT_PUBLIC_TOKEN: process.env.NEXT_PUBLIC_TOKEN,
CYPRESS_SEARCH_QUERY: 'test',
// importing the `API_PER_PAGE` variable from the constants file throws
// errors since this file doesn't follow ES6 syntax. if the value is
// changed in constants, it needs to be updated here too
API_PER_PAGE: 2000,
},
reporter: 'junit',
reporterOptions: {
mochaFile: 'cypress/results/results-[hash].xml',
toConsole: true,
},
});
})
41 changes: 3 additions & 38 deletions cypress/e2e/browse.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ describe('Browsing', () => {
emptyFixture: 'services/no-wares.json',
},
]

beforeEach(() => {
// Intercept the responses from the endpoint to view all requests.
// Even though this is to the same endpoint, the call happens on each page twice,
// Even though this is to the same endpoint, the call happens on each page twice,
// once when the page loads with all the wares, and again after any search is performed.
// this makes it necessary to create an intercept for each time the call is made.
intercepts.forEach((intercept) => {
Expand Down Expand Up @@ -103,39 +103,4 @@ describe('Browsing', () => {
})
})
})

describe('from the home page', () => {
beforeEach(() => {
wares = true
// Intercept the api call being made on the homepage
cy.customApiIntercept({
action: 'GET',
alias: 'useAllWares',
requestURL: `/providers/${Cypress.env('NEXT_PUBLIC_PROVIDER_ID')}/wares.json`,
data: wares,
defaultFixture: 'services/wares.json',
loading,
error
})
cy.visit('/')
})

context('a search is completed successfully and', () => {
it('navigates to "/browse" with a blank query', () => {
cy.get('button.search-button').click()
cy.url().should('include', '/browse')
cy.url().should('not.include', '?')
cy.get('input.search-bar').should('have.value', '')
cy.get(".card[data-cy='item-card']").should('be.visible')
})

it('navigates to "/browse" with a query term', () => {
cy.get('input.search-bar').type('test')
cy.get('button.search-button').click()
cy.url().should('include', '/browse?q=test')
cy.get('input.search-bar').should('have.value', 'test')
cy.get(".card[data-cy='item-card']").should('be.visible')
})
})
})
})
})
135 changes: 94 additions & 41 deletions cypress/e2e/home.cy.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,120 @@
describe('Viewing Home page', () => {
describe('Navigating to the home page', () => {
// declare variables that can be used to change how the response is intercepted.
let loading
let data = 'services/wares.json'
let error
let featuredServices

beforeEach(() => {
// Intercept the response from the endpoint to view all requests
cy.customApiIntercept({
action: 'GET',
alias: 'useAllWares',
requestURL: `/providers/${Cypress.env('NEXT_PUBLIC_PROVIDER_ID')}/wares.json`,
data: featuredServices,
defaultFixture: 'services/wares.json',
emptyFixture: 'services/no-wares.json',
loading,
error
data,
error,
requestURL: '/wares.json?per_page=2000',
})

cy.visit('/')
})


context('featured services list is loading', () => {
before(() => {
loading = true
describe('renders a search bar', () => {
it('with no query', () => {
cy.get("form[data-cy='search-bar']").should('exist').then(() => {
cy.log('Search bar renders successfully.')
})
})
it('should show 3 placeholder cards loading', () => {
cy.get('p.placeholder-glow').should('be.visible').then(() => {
cy.log('Loading text displays correctly.')

context('able to navigate to "/browse"', () => {
const testSetup = ({ data, defaultFixture, requestURL }) => {
cy.customApiIntercept({
alias: 'useFilteredWares',
data,
error,
requestURL,
})
}

it('with a blank query', () => {
testSetup({
data: 'services/wares.json',
requestURL: '/wares.json?per_page=2000&q=',
})

cy.get('button.search-button').click()
cy.url().should('include', '/browse')
cy.url().should('not.include', '?')
cy.get('input.search-bar').should('have.value', '')
cy.get(".card[data-cy='item-card']").should('be.visible')
})

it('with a valid query term', () => {
testSetup({
data: 'services/filtered-wares.json',
requestURL: `/wares.json?per_page=2000&q=${Cypress.env('CYPRESS_SEARCH_QUERY')}`,
})

cy.get('input.search-bar').type(Cypress.env('CYPRESS_SEARCH_QUERY'))
cy.get('button.search-button').click()
cy.url().should('include', `/browse?q=${Cypress.env('CYPRESS_SEARCH_QUERY')}`)
cy.get('input.search-bar').should('have.value', Cypress.env('CYPRESS_SEARCH_QUERY'))
cy.get(".card[data-cy='item-card']").should('be.visible')
})

it('with an invalid query term', () => {
const invalidQuery = 'asdfghjk'
testSetup({
data: 'services/no-wares.json',
requestURL: `/wares.json?per_page=2000&q=${invalidQuery}`,
})

cy.get('input.search-bar').type(invalidQuery)
cy.get('button.search-button').click()
cy.url().should('include', `/browse?q=${invalidQuery}`)
cy.get('input.search-bar').should('have.value', invalidQuery)
cy.get("p[data-cy='no-results']").should('contain', `Your search for ${invalidQuery} returned no results`)
})
})
})

context('error while making a request to the api', () => {
before(() => {
loading = false
error = true
})
it('should show an error message.', () => {
cy.get("div[role='alert']").should('be.visible').then(() => {
cy.log('Successfully hits an error.')
describe('renders a text box', () => {
it('showing the about text.', () => {
cy.get("section[data-cy='about-us-section']").should('exist').then(() => {
cy.log('Abouttext renders successfully.')
})
})
})

context('home page components are loading successfully, &', () => {
before(() => {
featuredServices = true
error = false
})
it('should show the search bar.', () => {
cy.get("form[data-cy='search-bar']").should('exist').then(() => {
cy.log('Search bar renders successfully.')
describe('makes a call to the api', () => {
context('which when given an invalid access token', () => {
before(() => {
data = undefined
error = {
body: {
message: 'No access token provided.',
},
statusCode: 403,
}
})

it('shows an error message', () => {
cy.get("div[role='alert']").should('be.visible').then(() => {
cy.log('Successfully hits an error.')
})
cy.get("div[role='alert']").contains('No access token provided.')
})
})
it('should show the about text.', () => {
cy.get("section[data-cy='about-us-section']").should('exist').then(() => {
cy.log('Abouttext renders successfully.')

context('which when returns no error or data', () => {
it('shows 3 placeholder cards loading', () => {
cy.get('p.placeholder-glow').should('have.length', 3).then(() => {
cy.log('Loading text displays correctly.')
})
})
})
it('should show the featured services cards.', () => {
cy.get("div[data-cy='item-group']").should('exist').then(() => {
cy.log('Status bar renders successfully.')

context('which when returns data', () => {
it('shows the featured services cards', () => {
cy.get("div[data-cy='item-group']").should('exist').then(() => {
cy.log('Status bar renders successfully.')
})
})
})
})
})
})
22 changes: 22 additions & 0 deletions cypress/fixtures/services/filtered-wares.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"ware_refs": [
{
"id": 3456,
"slug": "test-ware",
"name": "Test Ware",
"snippet": "Here is a test ware snippet.",
"urls": {
"promo_image": "https://y.yarn.co/193fa4ae-a245-4f7a-ac9d-64bbebb18c8d_screenshot.jpg"
}
},
{
"id": 4567,
"slug": "another-test-ware",
"name": "Another Test Ware",
"snippet": "Another test snippet.",
"urls": {
"promo_image": "https://cdn.drawception.com/images/panels/2017/7-2/jtqKRKSpyj-6.png"
}
}
]
}
56 changes: 26 additions & 30 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,47 +23,43 @@
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

import { scientistApiBaseURL } from './e2e'

// add a command to login that uses a session, so the user will remain logged in throughout the test file vs. needing to log in before each example.
// source: https://github.com/nextauthjs/next-auth/discussions/2053#discussioncomment-1191016
Cypress.Commands.add('login', (username, password) => {
cy.session([username, password], () => {
cy.intercept("/api/auth/session", { fixture: "session.json" }).as("session");
cy.intercept('/api/auth/session', { fixture: 'session.json' }).as('session')

// Set the cookie for cypress.
// It has to be a valid cookie so next-auth can decrypt it and confirm its validity.
// This cookie also may need to be refreshed intermittently if it expires
cy.setCookie("next-auth.session-token", Cypress.env('TEST_SESSION_COOKIE'));
// Set the cookie for cypress.
// It has to be a valid cookie so next-auth can decrypt it and confirm its validity.
// This cookie also may need to be refreshed intermittently if it expires
cy.setCookie('next-auth.session-token', Cypress.env('TEST_SESSION_COOKIE'))
})
})

// intercepts requests and creates potential cases for loading, error, data, and empty data
// required params are action, defaultFixture, requestURL
// optional params such as data, loading, and error can be passed depending on the creation of test cases that are related to that specific api call
/**
* This command intercepts requests and returns the given stubbed response
*
* @param {string} alias - the alias to give the intercept (convention is to
* use the function name)
* @param {string} data - the fixture to return as the response data
* @param {object} error - the error object to return as the response error
* @param {string} requestURL - the URL to intercept
*
* @returns {object} - the stubbed response
*/
Cypress.Commands.add('customApiIntercept', ({
action, alias, data, defaultFixture, emptyFixture, error, errorCaseStatusCode, loading, requestURL
alias, data, error, requestURL
}) => {
cy.intercept(action, scientistApiBaseURL + requestURL, (req) => {
switch (true) {
// reply with an empty response: both data and error will be undefined.
case loading: req.reply()
break

// error will be defined
case error: req.reply({ statusCode: errorCaseStatusCode || 500 })
break

// reply with a request body- default status code is 200
case data: req.reply({ fixture: defaultFixture })
break

// reply with the empty fixture is there is one, and the default as a backup. Allows us to isolate one api call at a time that may potentially respond with empty data.
case !data: req.reply({ fixture: emptyFixture || defaultFixture })
break

default: req.reply({ fixture: defaultFixture })
break
cy.intercept(`${scientistApiBaseURL}${requestURL}`, (req) => {
const response = {
data: data && { fixture: data },
error,
}

// falling back to an empty object mimics the loading state
return req.reply(response.data || response.error || {})
}).as(alias || 'customIntercept')
})
})
1 change: 1 addition & 0 deletions utils/api/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const fetcher = (url, token) => {
.then(res => res.data)
.catch(error => {
Sentry.captureException(error)
throw error
Copy link
Contributor Author

Choose a reason for hiding this comment

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

without this, we are only getting the placeholder cards on the homepage, instead of the error notice.

if we use return instead of throw, then the useSWR hook would incorrectly get the error as the data property:

{
  data: <AxiosError...>,
  error: undefined
}

})
}

Expand Down
Loading