test(frontend): Cover practically all the Storybook tests with snapshots (#14001)
@ -3,7 +3,7 @@ import { DecoratorFn } from '@storybook/react'
|
||||
/** Workaround for https://github.com/storybookjs/test-runner/issues/74 */
|
||||
// TODO: Smoke-test all the stories by removing this decorator, once all the stories pass
|
||||
export const withSnapshotsDisabled: DecoratorFn = (Story, { parameters }) => {
|
||||
if (parameters?.chromatic?.disableSnapshot && navigator.userAgent.includes('StorybookTestRunner')) {
|
||||
if (parameters?.testOptions?.skip && navigator.userAgent.includes('StorybookTestRunner')) {
|
||||
return <>Disabled for Test Runner</>
|
||||
}
|
||||
return <Story />
|
||||
|
@ -1,7 +1,7 @@
|
||||
const { createEntry } = require('../webpack.config')
|
||||
const babelConfig = require('../babel.config')
|
||||
import type { StorybookConfig } from '@storybook/react/types'
|
||||
import { createEntry } from '../webpack.config'
|
||||
|
||||
module.exports = {
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../frontend/src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
||||
addons: [
|
||||
{
|
||||
@ -19,28 +19,20 @@ module.exports = {
|
||||
'storybook-addon-pseudo-states',
|
||||
],
|
||||
staticDirs: ['public'],
|
||||
babel: async () => {
|
||||
// compile babel to "defaults" target (ES5)
|
||||
const envPreset = babelConfig.presets.find(
|
||||
(preset) => Array.isArray(preset) && preset[0] === '@babel/preset-env'
|
||||
)
|
||||
envPreset[1].targets = 'defaults'
|
||||
return babelConfig
|
||||
},
|
||||
webpackFinal: (config) => {
|
||||
const mainConfig = createEntry('main')
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
extensions: [...config.resolve.extensions, ...mainConfig.resolve.extensions],
|
||||
alias: { ...config.resolve.alias, ...mainConfig.resolve.alias },
|
||||
extensions: [...config.resolve!.extensions!, ...mainConfig.resolve.extensions],
|
||||
alias: { ...config.resolve!.alias, ...mainConfig.resolve.alias },
|
||||
},
|
||||
module: {
|
||||
...config.module,
|
||||
rules: [
|
||||
...mainConfig.module.rules,
|
||||
...config.module.rules.filter((rule) => rule.test.toString().includes('.mdx')),
|
||||
...config.module!.rules.filter((rule) => rule.test!.toString().includes('.mdx')),
|
||||
{
|
||||
test: /\.stories\.tsx?$/,
|
||||
use: [
|
||||
@ -59,3 +51,5 @@ module.exports = {
|
||||
postcss: false,
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
@ -1,6 +1,6 @@
|
||||
import '~/styles'
|
||||
import './storybook.scss'
|
||||
import type { Meta } from '@storybook/react'
|
||||
import type { Meta, Parameters } from '@storybook/react'
|
||||
import { worker } from '~/mocks/browser'
|
||||
import { loadPostHogJS } from '~/loadPostHogJS'
|
||||
import { getStorybookAppContext } from './app-context'
|
||||
@ -29,7 +29,7 @@ const setupPosthogJs = () => {
|
||||
setupPosthogJs()
|
||||
|
||||
/** Storybook global parameters. See https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters */
|
||||
export const parameters = {
|
||||
export const parameters: Parameters = {
|
||||
actions: { argTypesRegex: '^on[A-Z].*', disabled: true },
|
||||
controls: {
|
||||
matchers: {
|
||||
@ -51,7 +51,6 @@ export const parameters = {
|
||||
'Filters',
|
||||
'Layout',
|
||||
],
|
||||
includeName: true,
|
||||
},
|
||||
},
|
||||
viewMode: 'docs',
|
||||
|
@ -1,8 +1,35 @@
|
||||
import { toMatchImageSnapshot } from 'jest-image-snapshot'
|
||||
import { OptionsParameter } from '@storybook/addons'
|
||||
import { getStoryContext, TestRunnerConfig, TestContext } from '@storybook/test-runner'
|
||||
import { Locator, Page, LocatorScreenshotOptions } from 'playwright-core'
|
||||
import type { Locator, Page, LocatorScreenshotOptions } from 'playwright-core'
|
||||
import type { Mocks } from '~/mocks/utils'
|
||||
|
||||
// Extend Storybook interface `Parameters` with Chromatic parameters
|
||||
declare module '@storybook/react' {
|
||||
interface Parameters {
|
||||
options?: OptionsParameter
|
||||
layout?: 'padded' | 'fullscreen' | 'centered'
|
||||
testOptions?: {
|
||||
/** Whether the test should be a no-op (doesn't jest.skip as @storybook/test-runner doesn't allow that). **/
|
||||
skip?: boolean
|
||||
/**
|
||||
* Whether navigation (sidebar + topbar) should be excluded from the snapshot.
|
||||
* Warning: Fails if enabled for stories in which navigation is not present.
|
||||
*/
|
||||
excludeNavigationFromSnapshot?: boolean
|
||||
}
|
||||
mockDate?: string | number | Date
|
||||
msw?: {
|
||||
mocks?: Mocks
|
||||
}
|
||||
[name: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
const RETRY_TIMES = 3
|
||||
|
||||
const customSnapshotsDir = `${process.cwd()}/frontend/__snapshots__`
|
||||
const updateSnapshot = expect.getState().snapshotState._updateSnapshot === 'all'
|
||||
|
||||
async function expectStoryToMatchFullPageSnapshot(page: Page, context: TestContext): Promise<void> {
|
||||
await expectLocatorToMatchStorySnapshot(page, context)
|
||||
@ -15,13 +42,11 @@ async function expectStoryToMatchSceneSnapshot(page: Page, context: TestContext)
|
||||
async function expectStoryToMatchComponentSnapshot(page: Page, context: TestContext): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
const rootEl = document.getElementById('root')
|
||||
|
||||
if (rootEl) {
|
||||
// don't expand the container element to limit the screenshot
|
||||
// to the component's size
|
||||
rootEl.style.display = 'inline-block'
|
||||
}
|
||||
|
||||
// make the body transparent to take the screenshot
|
||||
// without background
|
||||
document.body.style.background = 'transparent'
|
||||
@ -35,7 +60,7 @@ async function expectLocatorToMatchStorySnapshot(
|
||||
context: TestContext,
|
||||
options?: LocatorScreenshotOptions
|
||||
): Promise<void> {
|
||||
const image = await locator.screenshot(options)
|
||||
const image = await locator.screenshot({ timeout: 3000, ...options })
|
||||
expect(image).toMatchImageSnapshot({
|
||||
customSnapshotsDir,
|
||||
customSnapshotIdentifier: context.id,
|
||||
@ -45,7 +70,7 @@ async function expectLocatorToMatchStorySnapshot(
|
||||
module.exports = {
|
||||
setup() {
|
||||
expect.extend({ toMatchImageSnapshot })
|
||||
jest.retryTimes(3, { logErrorsBeforeRetry: true })
|
||||
jest.retryTimes(RETRY_TIMES, { logErrorsBeforeRetry: true })
|
||||
},
|
||||
async postRender(page, context) {
|
||||
const storyContext = await getStoryContext(page, context)
|
||||
@ -55,13 +80,13 @@ module.exports = {
|
||||
document.body.classList.add('dangerously-stop-all-animations')
|
||||
})
|
||||
|
||||
if (!storyContext.parameters?.chromatic?.disableSnapshot) {
|
||||
if (!storyContext.parameters?.testOptions?.skip) {
|
||||
let expectStoryToMatchSnapshot: (page: Page, context: TestContext) => Promise<void>
|
||||
if (storyContext.parameters?.layout === 'fullscreen') {
|
||||
if (storyContext.parameters.testRunner?.includeNavigation) {
|
||||
expectStoryToMatchSnapshot = expectStoryToMatchFullPageSnapshot
|
||||
} else {
|
||||
if (storyContext.parameters.testOptions?.excludeNavigationFromSnapshot) {
|
||||
expectStoryToMatchSnapshot = expectStoryToMatchSceneSnapshot
|
||||
} else {
|
||||
expectStoryToMatchSnapshot = expectStoryToMatchFullPageSnapshot
|
||||
}
|
||||
} else {
|
||||
expectStoryToMatchSnapshot = expectStoryToMatchComponentSnapshot
|
||||
@ -70,7 +95,9 @@ module.exports = {
|
||||
// You'd expect that the 'load' state which @storybook/test-runner waits for would already mean
|
||||
// the story is ready, and definitely that 'networkidle' would indicate all assets to be ready.
|
||||
// But that's not the case, so we need to introduce a bit of a delay.
|
||||
await page.waitForTimeout(200)
|
||||
// The delay is extended when updating snapshots, so that we're 100% sure they represent the final state.
|
||||
const delayMultiplier: number = updateSnapshot ? RETRY_TIMES : 1
|
||||
await page.waitForTimeout(250 * delayMultiplier)
|
||||
await expectStoryToMatchSnapshot(page, context) // Don't retry when updating
|
||||
}
|
||||
},
|
||||
|
@ -18,5 +18,3 @@ RUN pnpm install
|
||||
COPY playwright.config.ts webpack.config.js babel.config.js tsconfig.json ./
|
||||
|
||||
COPY .storybook/ .storybook/
|
||||
|
||||
COPY frontend/ frontend/
|
||||
|
@ -12,6 +12,7 @@ module.exports = {
|
||||
{
|
||||
useBuiltIns: 'usage',
|
||||
corejs: 3,
|
||||
targets: 'defaults', // browserlist's defaults - https://github.com/browserslist/browserslist#full-list
|
||||
},
|
||||
],
|
||||
[
|
||||
|
@ -5,7 +5,9 @@ services:
|
||||
dockerfile: Dockerfile.playwright
|
||||
network_mode: host
|
||||
volumes:
|
||||
- './frontend/__snapshots__:/work/frontend/__snapshots__'
|
||||
# Mount the whole frontend/ directory to avoid to a new Docker image being generated each time
|
||||
# frontend code changes. Also, this allows frontend/__snapshots__/ to be updated.
|
||||
- './frontend:/work/frontend'
|
||||
- './playwright:/work/playwright'
|
||||
- './playwright-report:/work/playwright-report'
|
||||
- './test-results:/work/test-results'
|
||||
|
BIN
frontend/__snapshots__/components-insighttooltip--columns.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
frontend/__snapshots__/components-insighttooltip--default.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 21 KiB |
BIN
frontend/__snapshots__/components-sharing--dashboard-sharing.png
Normal file
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 18 KiB |
BIN
frontend/__snapshots__/components-sharing--insight-sharing.png
Normal file
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 82 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--lifecycle.png
Normal file
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 108 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--retention.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--stickiness.png
Normal file
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 168 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-area.png
Normal file
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 63 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-bar.png
Normal file
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 67 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-line.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-number.png
Normal file
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 56 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-pie.png
Normal file
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 38 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-table.png
Normal file
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 46 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-value.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--trends-world-map.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
frontend/__snapshots__/scenes-app-insights--user-paths.png
Normal file
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 64 KiB |
BIN
frontend/__snapshots__/scenes-app-saved-insights--card-view.png
Normal file
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 30 KiB |
BIN
frontend/__snapshots__/scenes-app-saved-insights--list-view.png
Normal file
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 52 KiB |
BIN
frontend/__snapshots__/scenes-other-invitesignup--cloud.png
Normal file
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 97 KiB |
BIN
frontend/__snapshots__/scenes-other-invitesignup--logged-in.png
Normal file
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 107 KiB |
BIN
frontend/__snapshots__/scenes-other-login--cloud.png
Normal file
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 90 KiB |
BIN
frontend/__snapshots__/scenes-other-login--self-hosted.png
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
frontend/__snapshots__/scenes-other-login--sso-error.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
frontend/__snapshots__/scenes-other-password-reset--initial.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
frontend/__snapshots__/scenes-other-password-reset--no-smtp.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
frontend/__snapshots__/scenes-other-password-reset--success.png
Normal file
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 14 KiB |
BIN
frontend/__snapshots__/scenes-other-preflight--preflight.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
frontend/__snapshots__/scenes-other-signup--cloud.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
frontend/__snapshots__/scenes-other-signup--self-hosted-sso.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
frontend/__snapshots__/scenes-other-signup--self-hosted.png
Normal file
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 12 KiB |
@ -13,7 +13,6 @@ export default {
|
||||
layout: 'fullscreen',
|
||||
options: { showPanel: false },
|
||||
viewMode: 'story',
|
||||
testRunner: { includeNavigation: true },
|
||||
},
|
||||
} as Meta
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { ActivityScope } from 'lib/components/ActivityLog/humanizeActivity'
|
||||
export default {
|
||||
title: 'Components/ActivityLog',
|
||||
component: ActivityLog,
|
||||
parameters: { chromatic: { disableSnapshot: true } }, // FIXME: Currently disabled as the Timeout story is flaky
|
||||
parameters: { testOptions: { skip: true } }, // FIXME: Currently disabled as the Timeout story is flaky
|
||||
decorators: [
|
||||
mswDecorator({
|
||||
get: {
|
||||
|
@ -11,7 +11,7 @@ export default {
|
||||
'Animations are [LottieFiles.com](https://lottiefiles.com/) animations that we load asynchronously.',
|
||||
},
|
||||
},
|
||||
chromatic: { disableSnapshot: true },
|
||||
testOptions: { skip: true }, // Animations aren't particularly snapshotable
|
||||
},
|
||||
argTypes: {
|
||||
size: {
|
||||
|
@ -5,7 +5,7 @@ export default {
|
||||
title: 'Components/Hedgehog Buddy',
|
||||
component: HedgehogBuddy,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
testOptions: { skip: true }, // Hedgehogs aren't particularly snapshotable
|
||||
},
|
||||
} as ComponentMeta<typeof HedgehogBuddy>
|
||||
|
||||
|
@ -8,9 +8,6 @@ import { personPropertiesModel } from '~/models/personPropertiesModel'
|
||||
export default {
|
||||
title: 'Filters/PropertyFilters',
|
||||
component: PropertyFilters,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} as ComponentMeta<typeof PropertyFilters>
|
||||
|
||||
const propertyFilters = [
|
||||
|
@ -10,9 +10,6 @@ import { cohortsModel } from '~/models/cohortsModel'
|
||||
export default {
|
||||
title: 'Filters/PropertyGroupFilters',
|
||||
component: PropertyGroupFilters,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} as ComponentMeta<typeof PropertyGroupFilters>
|
||||
|
||||
const propertyFilters = [
|
||||
|
@ -7,7 +7,7 @@ export default {
|
||||
title: 'Lemon UI/Icons/Property Icon',
|
||||
component: PropertyIcon,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true }, // There are too many icons, the snapshots get very big in table form
|
||||
testOptions: { skip: true }, // There are too many icons, the snapshots are huge in table form
|
||||
},
|
||||
} as ComponentMeta<typeof PropertyIcon>
|
||||
|
||||
|
@ -5,7 +5,6 @@ import { PropertyKeyInfo } from './PropertyKeyInfo'
|
||||
export default {
|
||||
title: 'Components/Property Key Info',
|
||||
component: PropertyKeyInfo,
|
||||
chromatic: { disableSnapshot: true },
|
||||
} as ComponentMeta<typeof PropertyKeyInfo>
|
||||
|
||||
const Template: ComponentStory<typeof PropertyKeyInfo> = (args) => {
|
||||
|
@ -19,7 +19,6 @@ export default {
|
||||
layout: 'fullscreen',
|
||||
options: { showPanel: false },
|
||||
viewMode: 'story',
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} as ComponentMeta<typeof SharingModal>
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default {
|
||||
layout: 'fullscreen',
|
||||
options: { showPanel: false },
|
||||
viewMode: 'story',
|
||||
chromatic: { disableSnapshot: true },
|
||||
mockDate: '2023-01-31 12:00:00',
|
||||
},
|
||||
} as ComponentMeta<typeof SubscriptionsModal>
|
||||
|
||||
|
@ -9,7 +9,7 @@ export default {
|
||||
title: 'Filters',
|
||||
decorators: [taxonomicFilterMocksDecorator],
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true }, // FIXME: This is currently excluded due to flaky loading of data in it
|
||||
testOptions: { skip: true }, // FIXME: This is currently excluded due to flaky loading of data in it
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default {
|
||||
title: 'Lemon UI/Hog illustrations',
|
||||
parameters: {
|
||||
options: { showPanel: false },
|
||||
chromatic: { disableSnapshot: true },
|
||||
testOptions: { skip: true }, // Not valuable to take snapshots of these hedgehogs
|
||||
docs: {
|
||||
description: {
|
||||
component: `
|
||||
|
@ -4,8 +4,12 @@ import { AlertMessage, AlertMessageProps } from './AlertMessage'
|
||||
export default {
|
||||
title: 'Lemon UI/Alert Message',
|
||||
component: AlertMessage,
|
||||
// See https://github.com/storybookjs/addon-smart-knobs/issues/63#issuecomment-995798227
|
||||
parameters: { actions: { argTypesRegex: null }, chromatic: { disableSnapshot: false } },
|
||||
parameters: {
|
||||
actions: {
|
||||
// See https://github.com/storybookjs/addon-smart-knobs/issues/63#issuecomment-995798227
|
||||
argTypesRegex: null,
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof AlertMessage>
|
||||
|
||||
const Template: ComponentStory<typeof AlertMessage> = (props: AlertMessageProps) => {
|
||||
|
@ -6,7 +6,6 @@ import { SurprisedHog, BlushingHog } from 'lib/components/hedgehogs'
|
||||
export default {
|
||||
title: 'Lemon UI/Lemon Select',
|
||||
component: LemonSelect,
|
||||
parameters: { chromatic: { disableSnapshot: false } },
|
||||
argTypes: {
|
||||
options: {
|
||||
defaultValue: [
|
||||
|
@ -7,8 +7,8 @@ export default {
|
||||
title: 'Lemon UI/Popover',
|
||||
component: Popover,
|
||||
parameters: {
|
||||
chromatic: {
|
||||
disableSnapshot: true, // FIXME: This story needs a play test for the popover to show up in snapshots
|
||||
testOptions: {
|
||||
skip: true, // FIXME: This story needs a play test for the popup to show up in snapshots
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof Popover>
|
||||
|
@ -20,7 +20,7 @@ export default {
|
||||
title: 'Lemon UI/Icons',
|
||||
parameters: {
|
||||
options: { showPanel: false },
|
||||
chromatic: { disableSnapshot: true }, // There are too many icons, the snapshots get very big in table form
|
||||
testOptions: { skip: true }, // There are too many icons, the snapshots are huge in table form
|
||||
docs: {
|
||||
description: {
|
||||
component: `
|
||||
|
@ -16,7 +16,7 @@ export const mswDecorator = (mocks: Mocks): DecoratorFunction<JSX.Element> => {
|
||||
for (const restMethod of Object.keys(rest)) {
|
||||
mergedMocks[restMethod] = {}
|
||||
// Ensure trailing slashes to avoid default handlers accidentally overshadowing story mocks
|
||||
for (const [path, handler] of Object.entries(parameters.msw.mocks?.[restMethod] || {})) {
|
||||
for (const [path, handler] of Object.entries(parameters.msw?.mocks?.[restMethod] || {})) {
|
||||
const cleanedPath = path.replace(/\/?$/, '/')
|
||||
mergedMocks[restMethod][cleanedPath] = handler
|
||||
}
|
||||
|
@ -467,7 +467,7 @@
|
||||
"is_debug": true,
|
||||
"is_event_property_usage_enabled": true,
|
||||
"licensed_users_available": 21311,
|
||||
"site_url": "http://localhost:8000",
|
||||
"site_url": "http://localhost:6006",
|
||||
"instance_preferences": {
|
||||
"debug_queries": false,
|
||||
"disable_paid_fs": false
|
||||
|