Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ jobs:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
with:
install: false
start: npm start
start: npm run mocks:ci, npm start
wait-on: 'http://localhost:3000'
command: npm run e2e
1 change: 0 additions & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module.exports = defineConfig({
},
baseUrl: 'http://localhost:3000',
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
supportFile: false,
},
component: {
devServer: {
Expand Down
62 changes: 59 additions & 3 deletions cypress/e2e/hackernewsStories.cy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
describe('Hackernews Stories App', () => {
beforeEach(() => {
cy.mocksRestoreRouteVariants()
cy.mocksSetDelay(0)

cy.intercept(
'GET',
'**/search**'
Expand All @@ -14,13 +17,66 @@ describe('Hackernews Stories App', () => {
.clear()
})

it('searches by a term and it returns another 100 results', () => {
it('searching by a term returns 5 results', () => {
cy.get('@searchField')
.type('Software Development Books{enter}')

cy.wait('@getStories')

cy.get('.table-row')
.should('have.length', 5)
})

it('searching by an odd term returns no reuslts', () => {
cy.mocksUseRouteVariant('get-stories:no-stories')

cy.get('@searchField')
.type('Odd term{enter}')

cy.wait('@getStories')

cy.get('.table-row')
.should('not.exist')
})

it('shows a loading fallback while fetching stories', () => {
cy.mocksSetDelay(1000)

cy.get('@searchField')
.type('react{enter}')
.type('Software Development Books{enter}')

cy.contains('Loading ...')
.as('loading')
.should('be.visible')

cy.wait('@getStories')

cy.get('.table-row')
.should('be.visible')
cy.get('@loading')
.should('not.exist')
})

it('shows one less story when dismissing the first one', () => {
cy.contains('button', 'Dismiss')
.click()

cy.get('.table-row')
.should('have.length', 4)
})

it('show five more results when clicking More', () => {
cy.intercept(
'GET',
'**/search?query=redux&page=1**'
).as('getNextStories')

cy.contains('button', 'More')
.click()

cy.wait('@getNextStories')

cy.get('.table-row')
.should('have.length', 100)
.should('have.length', 10)
})
})
3 changes: 3 additions & 0 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { register } from '@mocks-server/cypress-commands'

register()
106 changes: 106 additions & 0 deletions mocks.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// For a detailed explanation regarding each configuration property, visit:
// https://www.mocks-server.org/docs/configuration/how-to-change-settings
// https://www.mocks-server.org/docs/configuration/options

module.exports = {
// Log level. Can be one of silly, debug, verbose, info, warn or error
//log: "info",
config: {
// Allow unknown arguments
//allowUnknownArguments: false,
},
plugins: {
// Plugins to be registered
//register: [],
proxyRoutesHandler: {
},
adminApi: {
// Port number for the admin API server to be listening at
//port: 3110,
// Host for the admin API server
//host: "0.0.0.0",
https: {
// Use https protocol or not
//enabled: false,
// Path to a TLS/SSL certificate
//cert: undefined,
// Path to the certificate private key
//key: undefined,
},
},
inquirerCli: {
// Start interactive CLI or not
//enabled: true,
// Render emojis or not
//emojis: true,
},
openapi: {
collection: {
// Name for the collection created from OpenAPI definitions
//id: "openapi",
// Name of the collection to extend from
//from: undefined,
},
},
},
mock: {
routes: {
// Global delay to apply to routes
//delay: 0,
},
collections: {
// Selected collection
selected: "default",
},
},
server: {
// Port number for the server to be listening at
//port: 3100,
// Host for the server
//host: "0.0.0.0",
cors: {
// Use CORS middleware or not
//enabled: true,
// Options for the CORS middleware. Further information at https://github.com/expressjs/cors#configuration-options
//options: {"preflightContinue":false},
},
jsonBodyParser: {
// Use json body-parser middleware or not
//enabled: true,
// Options for the json body-parser middleware. Further information at https://github.com/expressjs/body-parser
//options: {},
},
urlEncodedBodyParser: {
// Use urlencoded body-parser middleware or not
//enabled: true,
// Options for the urlencoded body-parser middleware. Further information at https://github.com/expressjs/body-parser
//options: {"extended":true},
},
https: {
// Use https protocol or not
//enabled: false,
// Path to a TLS/SSL certificate
//cert: undefined,
// Path to the certificate private key
//key: undefined,
},
},
files: {
// Allows to disable files load
//enabled: true,
// Define folder from where to load collections and routes
//path: "mocks",
// Enable/disable files watcher
//watch: true,
babelRegister: {
// Load @babel/register
//enabled: false,
// Options for @babel/register
//options: {},
},
},
variantHandlers: {
// Variant Handlers to be registered
//register: [],
},
};
6 changes: 6 additions & 0 deletions mocks/collections.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = [
{
'id': 'default',
'routes': ['get-stories:five-stories']
},
]
86 changes: 86 additions & 0 deletions mocks/routes/stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const twoStories = require('../../cypress/fixtures/stories.json')
const threeStories = require('../../cypress/fixtures/incomplete.json')

const fiveStories = {
hits: [
...twoStories.list,
...threeStories.list
]
}

const nextStories = {
hits: [
{
"objectID": "6",
"title": "Clean Agile",
"author": "Robert C. Martin",
"url": "https://example.com/rm4",
"num_comments": 9983,
"points": 424
},
{
"objectID": "7",
"title": "Clean Craftsmanship",
"author": "Robert C. Martin",
"url": "https://example.com/rm5",
"num_comments": 134,
"points": 8487
},
{
"objectID": "8",
"title": "Composing Software",
"author": "Eric Elliott",
"url": "https://example.com/ee",
"num_comments": 99,
"points": 999
},
{
"objectID": "9",
"title": "The Programmer's Brain",
"author": "Felienne Hermans",
"url": "https://example.com/fh",
"num_comments": 349,
"points": 937
},
{
"objectID": "10",
"title": "A Philosophy of Software Design",
"author": "John Ousterhout",
"url": "https://example.com/jo",
"num_comments": 10001,
"points": 1000
},
]
}

module.exports = [
{
id: 'get-stories',
url: '*/search**',
method: 'GET',
variants: [
{
id: 'five-stories',
type: 'middleware',
options: {
middleware: (req, res) => {
res.status(200)
if (req.query.page === '0') {
res.send(fiveStories)
} else {
res.send(nextStories)
}
}
}
},
{
id: 'no-stories',
type: 'json',
options: {
status: 200,
body: { hits: [] }
}
},
]
}
]
Loading