Skip to content

Commit dfb706c

Browse files
committed
Merge branch 'main' into 363-request-specs
2 parents 0df8ebc + 60b689c commit dfb706c

File tree

6 files changed

+150
-112
lines changed

6 files changed

+150
-112
lines changed

cypress.config.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ module.exports = defineConfig({
2323
env: {
2424
TEST_SCIENTIST_USER: '[email protected]',
2525
TEST_SCIENTIST_PW: '!test1234',
26-
NEXT_PUBLIC_PROVIDER_NAME: 'acme',
27-
NEXT_PUBLIC_PROVIDER_ID: '572'
26+
NEXT_PUBLIC_PROVIDER_NAME: process.env.NEXT_PUBLIC_PROVIDER_NAME,
27+
NEXT_PUBLIC_PROVIDER_ID: process.env.NEXT_PUBLIC_PROVIDER_ID,
28+
NEXT_PUBLIC_TOKEN: process.env.NEXT_PUBLIC_TOKEN,
29+
CYPRESS_SEARCH_QUERY: 'test',
2830
},
2931
reporter: 'junit',
3032
reporterOptions: {
3133
mochaFile: 'cypress/results/results-[hash].xml',
3234
toConsole: true,
3335
},
34-
});
36+
})

cypress/e2e/browse.cy.js

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ describe('Browsing', () => {
1919
emptyFixture: 'services/no-wares.json',
2020
},
2121
]
22-
22+
2323
beforeEach(() => {
2424
// Intercept the responses from the endpoint to view all requests.
25-
// Even though this is to the same endpoint, the call happens on each page twice,
25+
// Even though this is to the same endpoint, the call happens on each page twice,
2626
// once when the page loads with all the wares, and again after any search is performed.
2727
// this makes it necessary to create an intercept for each time the call is made.
2828
intercepts.forEach((intercept) => {
@@ -103,39 +103,4 @@ describe('Browsing', () => {
103103
})
104104
})
105105
})
106-
107-
describe('from the home page', () => {
108-
beforeEach(() => {
109-
wares = true
110-
// Intercept the api call being made on the homepage
111-
cy.customApiIntercept({
112-
action: 'GET',
113-
alias: 'useAllWares',
114-
requestURL: `/providers/${Cypress.env('NEXT_PUBLIC_PROVIDER_ID')}/wares.json`,
115-
data: wares,
116-
defaultFixture: 'services/wares.json',
117-
loading,
118-
error
119-
})
120-
cy.visit('/')
121-
})
122-
123-
context('a search is completed successfully and', () => {
124-
it('navigates to "/browse" with a blank query', () => {
125-
cy.get('button.search-button').click()
126-
cy.url().should('include', '/browse')
127-
cy.url().should('not.include', '?')
128-
cy.get('input.search-bar').should('have.value', '')
129-
cy.get(".card[data-cy='item-card']").should('be.visible')
130-
})
131-
132-
it('navigates to "/browse" with a query term', () => {
133-
cy.get('input.search-bar').type('test')
134-
cy.get('button.search-button').click()
135-
cy.url().should('include', '/browse?q=test')
136-
cy.get('input.search-bar').should('have.value', 'test')
137-
cy.get(".card[data-cy='item-card']").should('be.visible')
138-
})
139-
})
140-
})
141-
})
106+
})

cypress/e2e/home.cy.js

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,120 @@
1-
describe('Viewing Home page', () => {
1+
describe('Navigating to the home page', () => {
22
// declare variables that can be used to change how the response is intercepted.
3-
let loading
3+
let data = 'services/wares.json'
44
let error
5-
let featuredServices
65

76
beforeEach(() => {
8-
// Intercept the response from the endpoint to view all requests
97
cy.customApiIntercept({
10-
action: 'GET',
118
alias: 'useAllWares',
12-
requestURL: `/providers/${Cypress.env('NEXT_PUBLIC_PROVIDER_ID')}/wares.json`,
13-
data: featuredServices,
14-
defaultFixture: 'services/wares.json',
15-
emptyFixture: 'services/no-wares.json',
16-
loading,
17-
error
9+
data,
10+
error,
11+
requestURL: '/wares.json?per_page=2000',
1812
})
13+
1914
cy.visit('/')
2015
})
2116

22-
23-
context('featured services list is loading', () => {
24-
before(() => {
25-
loading = true
17+
describe('renders a search bar', () => {
18+
it('with no query', () => {
19+
cy.get("form[data-cy='search-bar']").should('exist').then(() => {
20+
cy.log('Search bar renders successfully.')
21+
})
2622
})
27-
it('should show 3 placeholder cards loading', () => {
28-
cy.get('p.placeholder-glow').should('be.visible').then(() => {
29-
cy.log('Loading text displays correctly.')
23+
24+
context('able to navigate to "/browse"', () => {
25+
const testSetup = ({ data, defaultFixture, requestURL }) => {
26+
cy.customApiIntercept({
27+
alias: 'useFilteredWares',
28+
data,
29+
error,
30+
requestURL,
31+
})
32+
}
33+
34+
it('with a blank query', () => {
35+
testSetup({
36+
data: 'services/wares.json',
37+
requestURL: '/wares.json?per_page=2000&q=',
38+
})
39+
40+
cy.get('button.search-button').click()
41+
cy.url().should('include', '/browse')
42+
cy.url().should('not.include', '?')
43+
cy.get('input.search-bar').should('have.value', '')
44+
cy.get(".card[data-cy='item-card']").should('be.visible')
45+
})
46+
47+
it('with a valid query term', () => {
48+
testSetup({
49+
data: 'services/filtered-wares.json',
50+
requestURL: `/wares.json?per_page=2000&q=${Cypress.env('CYPRESS_SEARCH_QUERY')}`,
51+
})
52+
53+
cy.get('input.search-bar').type(Cypress.env('CYPRESS_SEARCH_QUERY'))
54+
cy.get('button.search-button').click()
55+
cy.url().should('include', `/browse?q=${Cypress.env('CYPRESS_SEARCH_QUERY')}`)
56+
cy.get('input.search-bar').should('have.value', Cypress.env('CYPRESS_SEARCH_QUERY'))
57+
cy.get(".card[data-cy='item-card']").should('be.visible')
58+
})
59+
60+
it('with an invalid query term', () => {
61+
const invalidQuery = 'asdfghjk'
62+
testSetup({
63+
data: 'services/no-wares.json',
64+
requestURL: `/wares.json?per_page=2000&q=${invalidQuery}`,
65+
})
66+
67+
cy.get('input.search-bar').type(invalidQuery)
68+
cy.get('button.search-button').click()
69+
cy.url().should('include', `/browse?q=${invalidQuery}`)
70+
cy.get('input.search-bar').should('have.value', invalidQuery)
71+
cy.get("p[data-cy='no-results']").should('contain', `Your search for ${invalidQuery} returned no results`)
3072
})
3173
})
3274
})
3375

34-
context('error while making a request to the api', () => {
35-
before(() => {
36-
loading = false
37-
error = true
38-
})
39-
it('should show an error message.', () => {
40-
cy.get("div[role='alert']").should('be.visible').then(() => {
41-
cy.log('Successfully hits an error.')
76+
describe('renders a text box', () => {
77+
it('showing the about text.', () => {
78+
cy.get("section[data-cy='about-us-section']").should('exist').then(() => {
79+
cy.log('Abouttext renders successfully.')
4280
})
4381
})
4482
})
4583

46-
context('home page components are loading successfully, &', () => {
47-
before(() => {
48-
featuredServices = true
49-
error = false
50-
})
51-
it('should show the search bar.', () => {
52-
cy.get("form[data-cy='search-bar']").should('exist').then(() => {
53-
cy.log('Search bar renders successfully.')
84+
describe('makes a call to the api', () => {
85+
context('which when given an invalid access token', () => {
86+
before(() => {
87+
data = undefined
88+
error = {
89+
body: {
90+
message: 'No access token provided.',
91+
},
92+
statusCode: 403,
93+
}
94+
})
95+
96+
it('shows an error message', () => {
97+
cy.get("div[role='alert']").should('be.visible').then(() => {
98+
cy.log('Successfully hits an error.')
99+
})
100+
cy.get("div[role='alert']").contains('No access token provided.')
54101
})
55102
})
56-
it('should show the about text.', () => {
57-
cy.get("section[data-cy='about-us-section']").should('exist').then(() => {
58-
cy.log('Abouttext renders successfully.')
103+
104+
context('which when returns no error or data', () => {
105+
it('shows 3 placeholder cards loading', () => {
106+
cy.get('p.placeholder-glow').should('have.length', 3).then(() => {
107+
cy.log('Loading text displays correctly.')
108+
})
59109
})
60110
})
61-
it('should show the featured services cards.', () => {
62-
cy.get("div[data-cy='item-group']").should('exist').then(() => {
63-
cy.log('Status bar renders successfully.')
111+
112+
context('which when returns data', () => {
113+
it('shows the featured services cards', () => {
114+
cy.get("div[data-cy='item-group']").should('exist').then(() => {
115+
cy.log('Status bar renders successfully.')
116+
})
64117
})
65118
})
66119
})
67-
})
120+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"ware_refs": [
3+
{
4+
"id": 3456,
5+
"slug": "test-ware",
6+
"name": "Test Ware",
7+
"snippet": "Here is a test ware snippet.",
8+
"urls": {
9+
"promo_image": "https://y.yarn.co/193fa4ae-a245-4f7a-ac9d-64bbebb18c8d_screenshot.jpg"
10+
}
11+
},
12+
{
13+
"id": 4567,
14+
"slug": "another-test-ware",
15+
"name": "Another Test Ware",
16+
"snippet": "Another test snippet.",
17+
"urls": {
18+
"promo_image": "https://cdn.drawception.com/images/panels/2017/7-2/jtqKRKSpyj-6.png"
19+
}
20+
}
21+
]
22+
}

cypress/support/commands.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,36 @@ import { scientistApiBaseURL } from './e2e'
44
// source: https://github.com/nextauthjs/next-auth/discussions/2053#discussioncomment-1191016
55
Cypress.Commands.add('login', (username, password) => {
66
cy.session([username, password], () => {
7-
cy.intercept("/api/auth/session", { fixture: "session.json" }).as("session");
7+
cy.intercept('/api/auth/session', { fixture: 'session.json' }).as('session')
88

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

16-
// intercepts requests and creates potential cases for loading, error, data, and empty data
17-
// required params are action, defaultFixture, requestURL
18-
// 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
16+
/**
17+
* This command intercepts requests and returns the given stubbed response
18+
*
19+
* @param {string} alias - the alias to give the intercept (convention is to
20+
* use the function name)
21+
* @param {string} data - the fixture to return as the response data
22+
* @param {object} error - the error object to return as the response error
23+
* @param {string} requestURL - the URL to intercept
24+
*
25+
* @returns {object} - the stubbed response
26+
*/
1927
Cypress.Commands.add('customApiIntercept', ({
20-
action, alias, data, defaultFixture, emptyFixture, error, errorCaseStatusCode, loading, requestURL
28+
alias, data, error, requestURL
2129
}) => {
22-
cy.intercept(action, scientistApiBaseURL + requestURL, (req) => {
23-
switch (true) {
24-
// reply with an empty response: both data and error will be undefined.
25-
case loading: req.reply()
26-
break
27-
28-
// error will be defined
29-
case error: req.reply({ statusCode: errorCaseStatusCode || 500 })
30-
break
31-
32-
// reply with a request body- default status code is 200
33-
case data: req.reply({ fixture: defaultFixture })
34-
break
35-
36-
// 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.
37-
case !data: req.reply({ fixture: emptyFixture || defaultFixture })
38-
break
39-
40-
default: req.reply({ fixture: defaultFixture })
41-
break
30+
cy.intercept(`${scientistApiBaseURL}${requestURL}`, (req) => {
31+
const response = {
32+
data: data && { fixture: data },
33+
error,
4234
}
35+
36+
// falling back to an empty object mimics the loading state
37+
return req.reply(response.data || response.error || {})
4338
}).as(alias || 'customIntercept')
44-
})
39+
})

utils/api/base.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const fetcher = (url, token) => {
1111
.then(res => res.data)
1212
.catch(error => {
1313
Sentry.captureException(error)
14+
throw error
1415
})
1516
}
1617

0 commit comments

Comments
 (0)