Skip to content

Commit

Permalink
Setup Testing (#92)
Browse files Browse the repository at this point in the history
* test: kickoff tests for Counter

* fix: missing types

* test: kickoff TimeSeries testing

* chore: yarn.lock

* test: kickoff Leaderboard testing

* test: set mockData for timeseries

* fix: import order

* test: set mockData for Counter

* refactor: getByRole instead of test id

* test: add additional query response tests for counter

* fix: remove unnecessary console.log

* chore: run tests with turbo instead of yarn workspaces
  • Loading branch information
felipecadavid committed Jul 7, 2023
1 parent 6504d53 commit 9c239bb
Show file tree
Hide file tree
Showing 38 changed files with 1,610 additions and 24 deletions.
5 changes: 3 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"env": {
"browser": true,
"es2022": true,
"node": true
"node": true,
"jest/globals": true
},
"extends": [
"eslint:recommended",
Expand All @@ -14,7 +15,7 @@
"prettier"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "react-hooks", "prettier"],
"plugins": ["@typescript-eslint", "react-hooks", "prettier", "jest"],
"settings": {
"react": {
"version": "detect"
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ node_modules
packages/**/*/generated
packages/nextjs/**

# testing
coverage

# parcel
.parcel-cache
dist
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"lint": "turbo run lint",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"release": "propel-release",
"test": "echo 'No tests yet'",
"test": "turbo run test",
"postinstall": "husky install",
"commit": "cz",
"storybook": "yarn workspace ui-kit-storybook storybook",
Expand Down Expand Up @@ -44,6 +44,7 @@
"cz-conventional-changelog": "^3.3.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.24.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
},
"devDependencies": {
"parcel": "^2.8.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.9.3"
},
"peerDependencies": {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
"graphql-request": "^6.1.0"
},
"peerDependencies": {
"graphql": "^16.6"
"graphql": "^16.6",
"react": "^16.8 || ^17 || ^18",
"react-dom": "^16.8 || ^17 || ^18"
},
"devDependencies": {
"@graphql-codegen/cli": "^4.0.1",
"@graphql-codegen/typescript": "^4.0.1",
"@graphql-codegen/typescript-operations": "^4.0.1",
"@graphql-codegen/typescript-react-query": "^4.1.0",
"parcel": "^2.8.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.9.4"
}
}
18 changes: 18 additions & 0 deletions packages/react/counter/jest-environment-jsdom.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const { TextEncoder, TextDecoder } = require('util')
const OriginalJSDOMEnvironment = require('jest-environment-jsdom')

Object.defineProperty(exports, '__esModule', {
value: true
})

class JSDOMEnvironment extends OriginalJSDOMEnvironment {
constructor (...args) {
const { global } = super(...args)
if (!global.TextEncoder) global.TextEncoder = TextEncoder
if (!global.TextDecoder) global.TextDecoder = TextDecoder
}
}

exports.default = JSDOMEnvironment
36 changes: 36 additions & 0 deletions packages/react/counter/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/

/** @type {import('jest').Config} */
const config = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'jsx'],
rootDir: '.',
roots: ['<rootDir>'],
moduleNameMapper: {
'@/testing/(.*)': '<rootDir>/testing/$1',
'@/testing': '<rootDir>/testing',
'@/counter/(.*)': '<rootDir>/src/(.*)',
'@/counter': '<rootDir>/src'
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: './jest-environment-jsdom.cjs',
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$'],
transform: {
'^.+\\.(js|ts|tsx)$': [
'@swc/jest',
{
jsc: {
transform: {
react: {
runtime: 'automatic'
}
}
}
}
]
}
}

module.exports = config
21 changes: 21 additions & 0 deletions packages/react/counter/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Optional: configure or set up a testing framework before each test.
// If you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`

// Used for __tests__/testing-library.js
// Learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'

import { server } from './testing/mocks/server'

process.env.NEXT_PUBLIC_ACCOUNT_MANAGEMENT_GRAPHQL_ENDPOINT ??= 'http://localhost:3000/in/graphql'
process.env.NEXT_PUBLIC_CONFIG_MANAGEMENT_GRAPHQL_ENDPOINT ??= 'http://localhost:3000/graphql'

// Establish API mocking before all tests.
beforeAll(() => server.listen())

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers())

// Clean up after the tests are finished.
afterAll(() => server.close())
18 changes: 17 additions & 1 deletion packages/react/counter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"types": "dist/index.d.ts",
"scripts": {
"dev": "parcel watch",
"build": "parcel build"
"build": "parcel build",
"test": "jest",
"test:coverage": "jest --ci --coverage --json --outputFile=coverage/coverage.json"
},
"publishConfig": {
"access": "public",
Expand All @@ -23,7 +25,21 @@
"graphql-request": "^6.1.0"
},
"devDependencies": {
"@swc/core": "^1.3.68",
"@swc/jest": "^0.2.26",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^27.5.1",
"@types/react": "latest",
"@types/react-dom": "latest",
"@types/testing-library__jest-dom": "^5.14.7",
"jest": "^27.5.1",
"jest-environment-jsdom": "^27.5.1",
"msw": "^1.2.2",
"parcel": "^2.8.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.9.3"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/counter/src/ErrorFallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface ErrorFallbackProps {
}

const Icon = ({ color }: { color?: string }) => (
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg role="img" width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.0006 14.8109C10.4831 14.8109 10.0984 15.2304 10.0984 15.7483C10.0984 16.2658 10.5183 16.6857 11.0006 16.6857C11.5181 16.6857 11.9029 16.2658 11.9029 15.7483C11.938 15.2288 11.5201 14.8109 11.0006 14.8109ZM11.0006 13.2486C11.346 13.2486 11.5904 12.9691 11.5904 12.6237V6.99937C11.5904 6.65395 11.3109 6.37445 11.0006 6.37445C10.6903 6.37445 10.3757 6.65567 10.3757 6.99937V12.6237C10.3757 12.9674 10.6569 13.2486 11.0006 13.2486ZM20.6986 16.2677L12.8949 3.0694C12.5004 2.40112 11.7896 2.00117 11.0006 2C10.2117 2 9.50472 2.39917 9.10633 3.06862L1.29871 16.2701C0.906184 16.9329 0.900326 17.7285 1.28224 18.3987C1.67718 19.0877 2.39037 19.4978 3.19301 19.4978H18.8121C19.6132 19.4978 20.3256 19.0865 20.7185 18.3976C21.1009 17.7285 21.0931 16.9317 20.6986 16.2677ZM19.5972 17.7441C19.4644 18.0722 19.1559 18.248 18.777 18.248H3.19301C2.84516 18.248 2.53762 18.0728 2.36967 17.7793C2.2104 17.4998 2.21286 17.1817 2.37577 16.9059L10.1843 3.70526C10.3523 3.42013 10.6569 3.24984 11.0006 3.24984C11.0006 3.24984 11 3.24984 11.0006 3.24984C11.343 3.25045 11.6474 3.4201 11.8154 3.70447L19.623 16.9059C19.7534 17.1817 19.7925 17.4981 19.5972 17.7441Z"
fill={color || '#475569'}
Expand Down
68 changes: 68 additions & 0 deletions packages/react/counter/src/__test__/Counter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react'
import { render, waitFor } from '@testing-library/react'

import { Counter, RelativeTimeRange } from '@/counter'
import { Dom } from '@/testing'

import { setupHandlers } from './mswHandlers'
import { counter } from './mockData'

describe('Counter', () => {
let dom: Dom

beforeEach(() => {
setupHandlers()
})

it('should render a static counter', async () => {
dom = render(<Counter value={counter.value} />)

await dom.findByText(counter.value)
})

it('should show value from server', async () => {
dom = render(
<Counter
query={{
metric: 'test-metric',
accessToken: 'test-token',
timeRange: { relative: RelativeTimeRange.LastNDays, n: 30 }
}}
/>
)

await dom.findByText(counter.value)
})

it('Should show "-" when value is null', async () => {
dom = render(
<Counter
query={{
metric: 'lack-of-data',
accessToken: 'test-token',
timeRange: { relative: RelativeTimeRange.LastNDays, n: 30 }
}}
/>
)

await waitFor(async () => {
await dom.findByText('-')
})
})

it('Should show error fallback when request fails', async () => {
dom = render(
<Counter
query={{
metric: 'should-fail',
accessToken: 'test-token',
timeRange: { relative: RelativeTimeRange.LastNDays, n: 30 }
}}
/>
)

await waitFor(async () => {
await dom.findByRole('img')
})
})
})
3 changes: 3 additions & 0 deletions packages/react/counter/src/__test__/mockData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const counter = {
value: '123'
}
41 changes: 41 additions & 0 deletions packages/react/counter/src/__test__/mswHandlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { graphql } from 'msw'

import { server } from '@/testing/mocks/server'

import { counter } from './mockData'

const handlers = [
graphql.query('Counter', (req, res, ctx) => {
const { metricName } = req.variables.counterInput

if (metricName === 'lack-of-data') {
return res(
ctx.data({
counter: {
value: null
}
})
)
}

if (metricName === 'should-fail') {
return res(
ctx.errors([
{
message: 'something went wrong'
}
])
)
}

return res(
ctx.data({
counter
})
)
})
]

export const setupHandlers = () => {
server.use(...handlers)
}
6 changes: 6 additions & 0 deletions packages/react/counter/testing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { render } from '@testing-library/react'

/**
* This is a convenience type for referring to the result of calling `render`.
*/
export type Dom = ReturnType<typeof render>
3 changes: 3 additions & 0 deletions packages/react/counter/testing/mocks/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { setupServer } from 'msw/node'

export const server = setupServer()
19 changes: 19 additions & 0 deletions packages/react/counter/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"baseUrl": ".",
"jsx": "preserve",
"target": "es2016",
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"paths": {
"@/testing/*": ["testing/*"],
"@/testing": ["testing"],
"@/counter": ["src"]
}
},
"include": ["**/*.ts", "**/*.tsx", "./jest.config.js", "./jest.setup.js"],
"exclude": ["node_modules"]
}
18 changes: 18 additions & 0 deletions packages/react/leaderboard/jest-environment-jsdom.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const { TextEncoder, TextDecoder } = require('util')
const OriginalJSDOMEnvironment = require('jest-environment-jsdom')

Object.defineProperty(exports, '__esModule', {
value: true
})

class JSDOMEnvironment extends OriginalJSDOMEnvironment {
constructor (...args) {
const { global } = super(...args)
if (!global.TextEncoder) global.TextEncoder = TextEncoder
if (!global.TextDecoder) global.TextDecoder = TextDecoder
}
}

exports.default = JSDOMEnvironment
36 changes: 36 additions & 0 deletions packages/react/leaderboard/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/

/** @type {import('jest').Config} */
const config = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'jsx'],
rootDir: '.',
roots: ['<rootDir>'],
moduleNameMapper: {
'@/testing/(.*)': '<rootDir>/testing/$1',
'@/testing': '<rootDir>/testing',
'@/leaderboard/(.*)': '<rootDir>/src/(.*)',
'@/leaderboard': '<rootDir>/src'
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js', 'jest-canvas-mock'],
testEnvironment: './jest-environment-jsdom.cjs',
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$'],
transform: {
'^.+\\.(js|ts|tsx)$': [
'@swc/jest',
{
jsc: {
transform: {
react: {
runtime: 'automatic'
}
}
}
}
]
}
}

module.exports = config
Loading

0 comments on commit 9c239bb

Please sign in to comment.