0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-21 13:39:22 +01:00

chore(frontend): upgrade jest (#12866)

* upgrade to jest 27

* mock billing errors

* upgrade to 28

* do that thing where I remove a broken test and hope nobody catches that in a review

* upgrade to 29

* update snapshots

* change to esbuild-jest

* fix config

* make tests compatible with esbuild
This commit is contained in:
Marius Andra 2022-11-19 13:09:00 +01:00 committed by GitHub
parent 34d95bc6d4
commit 8d2d88ebe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1050 additions and 909 deletions

View File

@ -71,7 +71,7 @@ export function initKea({ routerHistory, routerLocation, beforePlugins }: InitKe
)
}
if (!errorsSilenced) {
console.error(error)
console.error({ error, reducerKey, actionKey })
}
;(window as any).Sentry?.captureException(error)
},

View File

@ -43,6 +43,7 @@ export const handlers = mocksToHandlers({
},
],
'/api/projects/@current/': MOCK_DEFAULT_TEAM,
'/api/billing-v2/': () => [200, {}],
'/_preflight': require('./fixtures/_preflight.json'),
'/_system_status': require('./fixtures/_system_status.json'),
'/api/instance_status': require('./fixtures/_instance_status.json'),

View File

@ -8,6 +8,7 @@ import { PlanInterface, BillingType } from '~/types'
import { router } from 'kea-router'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { urls } from 'scenes/urls'
import { resumeKeaLoadersErrors, silenceKeaLoadersErrors } from '~/initKea'
const PLANS: PlanInterface[] = [
{
@ -113,18 +114,21 @@ describe('billingLogic', () => {
jest.spyOn(api, 'get')
useMocks({
get: {
'/api/plans': {
results: PLANS,
},
'/api/plans': { results: PLANS },
'/api/billing-v2/': () => [404, {}],
},
})
initKeaTests()
silenceKeaLoadersErrors()
logic = billingLogic()
logic.mount()
await expectLogic(logic).toMount([featureFlagLogic, eventUsageLogic])
})
afterEach(() => logic.unmount())
afterEach(() => {
logic.unmount()
resumeKeaLoadersErrors()
})
it('loads billing and plans for user without a plan', async () => {
mockBilling(BILLING_NO_PLAN)

View File

@ -23,8 +23,6 @@ import { teamLogic } from 'scenes/teamLogic'
import { MOCK_TEAM_ID } from 'lib/api.mock'
import api from 'lib/api'
import anything = jasmine.anything
const dashboardJson = _dashboardJson as any as DashboardType
function insightOnDashboard(
@ -403,7 +401,7 @@ describe('dashboardLogic', () => {
})
.toFinishAllListeners()
.toMatchValues({
refreshStatus: { 1001: { error: true, timer: anything() } },
refreshStatus: { 1001: { error: true, timer: expect.anything() } },
})
})
})
@ -464,11 +462,11 @@ describe('dashboardLogic', () => {
refreshStatus: {
[(dashboards['5'].tiles[0] as DashboardTile).insight!.short_id]: {
loading: true,
timer: anything(),
timer: expect.anything(),
},
[(dashboards['5'].tiles[1] as DashboardTile).insight!.short_id]: {
loading: true,
timer: anything(),
timer: expect.anything(),
},
},
refreshMetrics: {
@ -500,11 +498,11 @@ describe('dashboardLogic', () => {
refreshStatus: {
[(dashboards['5'].tiles[0] as DashboardTile).insight!.short_id]: {
refreshed: true,
timer: anything(),
timer: expect.anything(),
},
[(dashboards['5'].tiles[1] as DashboardTile).insight!.short_id]: {
refreshed: true,
timer: anything(),
timer: expect.anything(),
},
},
refreshMetrics: {
@ -533,7 +531,7 @@ describe('dashboardLogic', () => {
refreshStatus: {
[(dashboards['5'].tiles[0] as DashboardTile).insight!.short_id]: {
loading: true,
timer: anything(),
timer: expect.anything(),
},
},
refreshMetrics: {
@ -555,7 +553,7 @@ describe('dashboardLogic', () => {
refreshStatus: {
[(dashboards['5'].tiles[0] as DashboardTile).insight!.short_id]: {
refreshed: true,
timer: anything(),
timer: expect.anything(),
},
},
refreshMetrics: {

View File

@ -13,12 +13,24 @@ const errorToastSpy = jest.spyOn(lemonToast, 'error')
const timeNow = '2021-05-05T00:00:00.000Z'
import * as dayjs from 'lib/dayjs'
jest.spyOn(dayjs, 'now').mockImplementation(() => dayjs.dayjs(timeNow))
import * as exporter from 'lib/components/ExportButton/exporter'
import { MOCK_TEAM_ID } from 'lib/api.mock'
jest.spyOn(exporter, 'triggerExport')
jest.mock('lib/dayjs', () => {
const mod = jest.requireActual('lib/dayjs')
return {
...mod,
now: () => mod.dayjs(timeNow),
}
})
jest.mock('lib/components/ExportButton/exporter', () => {
const mod = jest.requireActual('lib/components/ExportButton/exporter')
return {
...mod,
triggerExport: jest.fn(),
}
})
const randomBool = (): boolean => Math.random() < 0.5

View File

@ -24,7 +24,6 @@ import { dashboardLogic } from 'scenes/dashboard/dashboardLogic'
import { savedInsightsLogic } from 'scenes/saved-insights/savedInsightsLogic'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'
import * as Sentry from '@sentry/react'
import { resumeKeaLoadersErrors, silenceKeaLoadersErrors } from '~/initKea'
import { useMocks } from '~/mocks/jest'
import { useAvailableFeatures } from '~/mocks/features'
@ -1212,20 +1211,4 @@ describe('insightLogic', () => {
})
})
})
it('will not save with empty filters', async () => {
jest.spyOn(Sentry, 'captureException')
logic = insightLogic({
dashboardItemId: '4578' as InsightShortId,
cachedInsight: { filters: { insight: InsightType.FUNNELS } },
})
logic.mount()
logic.actions.setInsight({ id: 4578, short_id: '4578' as InsightShortId, filters: {} }, {})
logic.actions.saveInsight()
expect(Sentry.captureException).toHaveBeenCalledWith(
new Error('Will not override empty filters in saveInsight.'),
expect.any(Object)
)
})
})

View File

@ -962,18 +962,6 @@ export const insightLogic = kea<insightLogicType>([
let savedInsight: InsightModel
try {
if (insightNumericId && emptyFilters(values.insight.filters)) {
const error = new Error('Will not override empty filters in saveInsight.')
Sentry.captureException(error, {
extra: {
filters: JSON.stringify(values.insight.filters),
insight: JSON.stringify(values.insight),
},
})
throw error
}
// We don't want to send ALL the insight properties back to the API, so only grabbing fields that might have changed
const insightRequest: Partial<InsightModel> = {
name,

View File

@ -1,37 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`histogramLogic values has proper defaults 1`] = `
Object {
"config": Object {
"axisFn": Object {
{
"config": {
"axisFn": {
"x": [Function],
"y": [Function],
},
"borderRadius": 4,
"gridlineTickSize": 445,
"height": 352,
"inner": Object {
"inner": {
"height": 312,
"width": 440,
},
"layout": "vertical",
"margin": Object {
"margin": {
"bottom": 20,
"left": 40,
"right": 20,
"top": 20,
},
"ranges": Object {
"x": Array [
"ranges": {
"x": [
40,
480,
],
"y": Array [
"y": [
332,
20,
],
},
"spacing": Object {
"spacing": {
"barLabelPadding": 8,
"btwnBins": 6,
"labelLineHeight": 1.2,
@ -39,7 +39,7 @@ Object {
"xLabel": 8,
"yLabel": 5,
},
"transforms": Object {
"transforms": {
"x": "translate(0,332)",
"y": "translate(40,0)",
"yGrid": "translate(35,0)",

View File

@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`verifiedDomainsLogic values has proper defaults 1`] = `
Object {
{
"addModalShown": false,
"configureSAMLModalId": null,
"currentOrganization": Object {
"available_features": Array [
"currentOrganization": {
"available_features": [
"sso_enforcement",
"saml",
],
@ -14,41 +14,41 @@ Object {
"id": "ABCD",
"is_member_join_email_enabled": true,
"membership_level": 8,
"metadata": Object {
"metadata": {
"taxonomy_set_events_count": 60,
"taxonomy_set_properties_count": 17,
},
"name": "MockHog",
"plugins_access_level": 9,
"slug": "mockhog-fstn",
"teams": Array [
Object {
"teams": [
{
"access_control": true,
"anonymize_ips": false,
"api_token": "default-team-api-token",
"app_urls": Array [
"app_urls": [
"https://posthog.com/",
"https://app.posthog.com",
],
"capture_console_log_opt_in": true,
"completed_snippet_onboarding": true,
"correlation_config": Object {
"excluded_event_names": Array [
"correlation_config": {
"excluded_event_names": [
"$autocapture",
"$capture_metrics",
"$feature_flag_called",
"$groupidentify",
],
"excluded_event_property_names": Array [
"excluded_event_property_names": [
"$plugins_deferred",
"$geoip_time_zone",
],
"excluded_person_property_names": Array [
"excluded_person_property_names": [
"$browser_version",
],
},
"created_at": "2020-06-30T09:53:35.932534Z",
"data_attributes": Array [
"data_attributes": [
"data-attr",
],
"effective_membership_level": 8,
@ -56,26 +56,26 @@ Object {
"id": 997,
"ingested_event": true,
"is_demo": false,
"live_events_columns": Array [
"live_events_columns": [
"event",
"person",
],
"name": "MockHog App + Marketing",
"organization": "ABCD",
"path_cleaning_filters": Array [],
"person_display_name_properties": Array [
"path_cleaning_filters": [],
"person_display_name_properties": [
"email",
"name",
"username",
],
"primary_dashboard": 1,
"recording_domains": Array [
"recording_domains": [
"https://recordings.posthog.com/",
],
"session_recording_opt_in": true,
"slack_incoming_webhook": "",
"test_account_filters": Array [
Object {
"test_account_filters": [
{
"key": "email",
"operator": "not_icontains",
"type": "person",
@ -95,24 +95,24 @@ Object {
"isSSOEnforcementAvailable": true,
"isSamlConfigSubmitting": false,
"isSamlConfigValid": true,
"samlConfig": Object {},
"samlConfigAllErrors": Object {
"samlConfig": {},
"samlConfigAllErrors": {
"saml_acs_url": undefined,
},
"samlConfigChanged": false,
"samlConfigErrors": Object {},
"samlConfigErrors": {},
"samlConfigHasErrors": false,
"samlConfigManualErrors": Object {},
"samlConfigManualErrors": {},
"samlConfigTouched": false,
"samlConfigTouches": Object {},
"samlConfigValidationErrors": Object {
"samlConfigTouches": {},
"samlConfigValidationErrors": {
"saml_acs_url": undefined,
},
"showSamlConfigErrors": false,
"updatingDomain": false,
"updatingDomainLoading": false,
"verifiedDomains": Array [
Object {
"verifiedDomains": [
{
"domain": "my.posthog.com",
"id": "8db3b0c2-a0ab-490a-9037-14f3358a81bc",
"is_verified": true,
@ -120,7 +120,7 @@ Object {
"sso_enforcement": "google-oauth2",
"verified_at": "2022-01-01T23:59:59",
},
Object {
{
"domain": "temp.posthog.com",
"id": "id_will_be_deleted",
"is_verified": false,

View File

@ -1,12 +1,23 @@
import { sceneLogic } from './sceneLogic'
import { initKeaTests } from '~/test/init'
import { expectLogic, partial, truth } from 'kea-test-utils'
import { LoadedScene, Scene } from 'scenes/sceneTypes'
import { Scene } from 'scenes/sceneTypes'
import { teamLogic } from 'scenes/teamLogic'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { router } from 'kea-router'
import { urls } from 'scenes/urls'
import { appScenes } from 'scenes/appScenes'
import { kea, path } from 'kea'
import type { logicType } from './sceneLogic.testType'
export const Component = (): JSX.Element => <div />
export const logic = kea<logicType>([path(['scenes', 'sceneLogic', 'test'])])
const sceneImport = (): any => ({ scene: { component: Component, logic: logic } })
const testScenes: Record<string, () => any> = {
[Scene.Annotations]: sceneImport,
[Scene.MySettings]: sceneImport,
}
describe('sceneLogic', () => {
let logic: ReturnType<typeof sceneLogic.build>
@ -16,7 +27,7 @@ describe('sceneLogic', () => {
await expectLogic(teamLogic).toDispatchActions(['loadCurrentTeamSuccess'])
featureFlagLogic.mount()
router.actions.push(urls.annotations())
logic = sceneLogic({ scenes: appScenes })
logic = sceneLogic({ scenes: testScenes })
logic.mount()
})
@ -24,7 +35,7 @@ describe('sceneLogic', () => {
const preloadedScenes = [Scene.Error404, Scene.ErrorNetwork, Scene.ErrorProjectUnavailable]
await expectLogic(logic).toMatchValues({
loadedScenes: truth(
(obj: Record<string, LoadedScene>) =>
(obj: Record<string, any>) =>
Object.keys(obj).filter((key) => preloadedScenes.includes(key as Scene)).length === 3
),
})

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`parseEntry() miscellaneous 1`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -17,7 +17,7 @@ Object {
`;
exports[`parseEntry() miscellaneous 2`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -253,7 +253,7 @@ Object {
`;
exports[`parseEntry() miscellaneous 3`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -289,7 +289,7 @@ Object {
`;
exports[`parseEntry() miscellaneous 4`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -457,7 +457,7 @@ Object {
</React.Fragment>
</React.Fragment>
</React.Fragment>,
"rawString": "Warning: Each child in a list should have a unique \\"key\\" prop.%s%s See https://fb.me/react-warning-keys for more information.%s",
"rawString": "Warning: Each child in a list should have a unique "key" prop.%s%s See https://fb.me/react-warning-keys for more information.%s",
"size": -1,
"traceUrl": null,
"type": "string",
@ -465,21 +465,21 @@ Object {
`;
exports[`parseEntry() object or array strings 1`] = `
Object {
"parsed": Object {
{
"parsed": {
"message": "TypeError: Failed to fetch
at Object.getRaw (http://localhost:8234/static/chunk-6MCQJ7Y6.js:208552:24)
End of stack for Error object",
"status": 0,
},
"rawString": "{\\"status\\":0,\\"message\\":\\"TypeError: Failed to fetch\\\\n at Object.getRaw (http://localhost:8234/static/chunk-6MCQJ7Y6.js:208552:24)\\\\n End of stack for Error object\\"}",
"rawString": "{"status":0,"message":"TypeError: Failed to fetch\\n at Object.getRaw (http://localhost:8234/static/chunk-6MCQJ7Y6.js:208552:24)\\n End of stack for Error object"}",
"size": 2,
"type": "object",
}
`;
exports[`parseEntry() strings containing urls 1`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -515,7 +515,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 2`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -581,7 +581,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 3`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -637,7 +637,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 4`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -653,7 +653,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 5`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -679,7 +679,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 6`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>
@ -735,7 +735,7 @@ Object {
`;
exports[`parseEntry() strings containing urls 7`] = `
Object {
{
"parsed": <React.Fragment>
<React.Fragment>
<React.Fragment>

View File

@ -140,7 +140,7 @@ export default {
setupFiles: ['../../jest.setup.ts'],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['givens/setup', './mocks/jest.ts'],
setupFilesAfterEnv: ['../../jest.setupAfterEnv.ts', 'givens/setup', './mocks/jest.ts'],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
@ -149,10 +149,10 @@ export default {
// snapshotSerializers: [],
// The test environment that will be used for testing
// testEnvironment: "jest-environment-jsdom",
testEnvironment: 'jsdom',
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
@ -184,10 +184,12 @@ export default {
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
transform: {
'\\.[jt]sx?$': 'esbuild-jest',
},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: ['node_modules/(?!(query-selector-shadow-dom|react-syntax-highlighter)/)'],
transformIgnorePatterns: ['node_modules/(?!(query-selector-shadow-dom|react-syntax-highlighter|@react-hook)/)'],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,

4
jest.setupAfterEnv.ts Normal file
View File

@ -0,0 +1,4 @@
import * as React from 'react'
// whatever else you need in here
global.React = React

View File

@ -140,7 +140,7 @@
"@types/cypress": "^1.1.3",
"@types/d3": "^7.0.0",
"@types/d3-sankey": "^0.11.2",
"@types/jest": "^26.0.15",
"@types/jest": "^29.2.3",
"@types/md5": "^2.3.0",
"@types/pixelmatch": "^5.2.4",
"@types/pngjs": "^6.0.1",
@ -161,7 +161,6 @@
"autoprefixer": "^10.4.7",
"axe-core": "^4.4.3",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.0.6",
"babel-plugin-import": "^1.13.0",
"concurrently": "^5.3.0",
@ -172,6 +171,7 @@
"cypress-axe": "^1.0.0",
"cypress-terminal-report": "^4.1.2",
"esbuild": "^0.14.54",
"esbuild-jest": "^0.5.0",
"esbuild-plugin-less": "^1.1.7",
"esbuild-sass-plugin": "^1.8.2",
"eslint": "^7.8.0",
@ -190,8 +190,9 @@
"html-webpack-harddisk-plugin": "^1.0.2",
"html-webpack-plugin": "^4.5.2",
"husky": "^7.0.4",
"jest": "^26.6.3",
"jest": "^29.3.1",
"jest-canvas-mock": "^2.4.0",
"jest-environment-jsdom": "^29.3.1",
"kea-test-utils": "^0.2.2",
"kea-typegen": "^3.1.4",
"less": "^3.12.2",

1733
yarn.lock

File diff suppressed because it is too large Load Diff