Skip to content

Commit

Permalink
Merge pull request #373 from scientist-softserv/361-fix-home-specs
Browse files Browse the repository at this point in the history
361 fix home specs
  • Loading branch information
alishaevn authored Feb 14, 2024
2 parents e56fad6 + 11f0bc9 commit 60b689c
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 112 deletions.
8 changes: 5 additions & 3 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ 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',
},
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
})
}

Expand Down

0 comments on commit 60b689c

Please sign in to comment.