Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
silesky committed Dec 11, 2024
1 parent 5caf4d6 commit 9041c59
Show file tree
Hide file tree
Showing 29 changed files with 1,155 additions and 101 deletions.
32 changes: 15 additions & 17 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@
"request": "launch",
"name": "Jest Current File",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"--testTimeout=100000",
"--findRelatedTests",
"${relativeFile}"
],
"args": ["--testTimeout=100000", "--findRelatedTests", "${relativeFile}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"type": "node",
Expand All @@ -30,9 +24,17 @@
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Run Jest Tests for Current Package",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--testTimeout=100000"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"cwd": "${fileDirname}"
},
{
"type": "node",
Expand All @@ -47,9 +49,7 @@
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"type": "node",
Expand All @@ -64,9 +64,7 @@
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
"skipFiles": [
"<node_internals>/**"
]
"skipFiles": ["<node_internals>/**"]
},
{
"name": "ts-node Current File",
Expand Down
3 changes: 2 additions & 1 deletion packages/signals/signals-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"scripts": {
".": "yarn run -T turbo run --filter=@internal/signals-integration-tests...",
"build": "webpack",
"test": "playwright test",
"test": "playwright test src/tests/signals-vanilla",
"test:perf": "playwright test src/tests/performance",
"watch": "webpack -w",
"lint": "yarn concurrently 'yarn:eslint .' 'yarn:tsc --noEmit'",
"concurrently": "yarn run -T concurrently",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const config: PlaywrightTestConfig = {
use: {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on',
launchOptions: {
args: ['--enable-precise-memory-info'],
},
},

/* Configure projects for major browsers */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { BasePage } from '../../helpers/base-page-object'

export class IndexPage extends BasePage {
constructor() {
super(`/performance/index.html`)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<script src="../../../dist/signals-vanilla.bundle.js"></script>
<!-- Dummy favicon -->
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>

<body>
<div id="test-container"></div>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { test } from '@playwright/test'
import { IndexPage } from './index-page'
import { sleep } from '@segment/analytics-core'

declare global {
interface Performance {
memory: {
usedJSHeapSize: number
totalJSHeapSize: number
}
}
}

const basicEdgeFn = `
// this is a process signal function
const processSignal = (signal) => {
if (signal.type === 'interaction') {
const eventName = signal.data.eventType + ' ' + '[' + signal.type + ']'
analytics.track(eventName, signal.data)
}
}`

let indexPage: IndexPage

test.beforeEach(async ({ page }) => {
indexPage = await new IndexPage().loadAndWait(page, basicEdgeFn)
})

test('memory leak', async ({ page }) => {
await indexPage.waitForSignalsApiFlush()
const ALLOWED_GROWTH = 1.1
const getMemoryUsage = (): Promise<number> =>
page.evaluate(() => {
return performance.memory.usedJSHeapSize
})

const firstMemory = await getMemoryUsage()

// add nodes
await page.evaluate(() => {
const target = document.getElementById('test-container')!
const NODE_COUNT = 2000
for (let i = 0; i < NODE_COUNT; i++) {
const newNode = document.createElement('input')
newNode.type = 'text'
newNode.value = Math.random().toString()
target.appendChild(newNode)
}
})

await sleep(3000)

// remove all the nodes
await page.evaluate(() => {
const target = document.getElementById('test-container')!
while (target.firstChild) {
target.removeChild(target.firstChild)
}
})

// Analyze memory usage
await sleep(3000)
const lastMemory = await getMemoryUsage()

// Allow some fluctuation, but fail if there's a significant memory increase
if (lastMemory > firstMemory * ALLOWED_GROWTH) {
throw new Error(
`Memory leak detected! Initial: ${firstMemory}, Final: ${lastMemory}. Threshold`
)
} else {
console.log(
'Memory leak test passed!',
`initial: ${firstMemory}, final: ${lastMemory}, allowed growth: ${ALLOWED_GROWTH}`
)
}
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test, expect } from '@playwright/test'
import { IndexPage } from './index-page'
import { waitForCondition } from '../../helpers/playwright-utils'

const indexPage = new IndexPage()

Expand Down Expand Up @@ -56,6 +57,10 @@ test('debug ingestion disabled and sample rate 1 -> will send the signal', async
sampleRate: 1,
}
)
await indexPage.fillNameInput('John Doe')
expect(indexPage.signalsAPI.getEvents('interaction')).toHaveLength(1)
await Promise.all([
indexPage.fillNameInput('John Doe'),
waitForCondition(
() => indexPage.signalsAPI.getEvents('interaction').length > 0
),
])
})
6 changes: 4 additions & 2 deletions packages/signals/signals-runtime/src/web/web-signals-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ type SubmitData = {
target: SerializedTarget
}

type ChangeData = {
export type ChangeData = {
eventType: 'change'
[key: string]: unknown
target: SerializedTarget
listener: 'contenteditable' | 'onchange' | 'mutation'
change: JSONValue
}

export type InteractionSignal = RawSignal<'interaction', InteractionData>
Expand Down
2 changes: 1 addition & 1 deletion packages/signals/signals/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"build:bundle": "NODE_ENV=production yarn run webpack",
"workerbox": "node scripts/build-workerbox.js",
"assert-generated": "sh scripts/assert-workerbox-built.sh",
"watch": "yarn concurrently 'yarn build:bundle --watch' 'yarn build:esm --watch'",
"watch": "rm -rf dist && yarn concurrently 'yarn build:bundle --watch' 'yarn build:esm --watch'",
"version": "sh scripts/version.sh",
"watch:test": "yarn test --watch",
"tsc": "yarn run -T tsc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ describe(getSignalBuffer, () => {
})

it('should delete older signals when maxBufferSize is exceeded', async () => {
const signals = range(15).map((_, idx) =>
const signals = range(15).map(() =>
createInteractionSignal({
idx: idx,
change: 'change',
eventType: 'change',
listener: 'listener',
target: {},
})
)
Expand All @@ -46,9 +47,10 @@ describe(getSignalBuffer, () => {
})

it('should delete older signals on initialize if current number exceeds maxBufferSize', async () => {
const signals = range(15).map((_, idx) =>
const signals = range(15).map((_) =>
createInteractionSignal({
idx: idx,
change: { foo: 'bar' },
listener: 'onchange',
eventType: 'change',
target: {},
})
Expand Down Expand Up @@ -103,10 +105,11 @@ describe(getSignalBuffer, () => {
})

it('should delete older signals when maxBufferSize is exceeded', async () => {
const signals = range(15).map((_, idx) =>
const signals = range(15).map(() =>
createInteractionSignal({
idx: idx,
eventType: 'change',
change: { foo: 'bar' },
listener: 'onchange',
target: {},
})
)
Expand Down
44 changes: 44 additions & 0 deletions packages/signals/signals/src/core/client/__tests__/redact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,59 @@ describe(redactSignalData, () => {
it('should redact the value in the "target" property if the type is "interaction"', () => {
const signal = factories.createInteractionSignal({
eventType: 'change',
change: { value: 'secret' },
listener: 'onchange',
target: { value: 'secret', formData: { password: '123' } },
})
const expected = factories.createInteractionSignal({
eventType: 'change',
change: { value: 'XXX' },
listener: 'onchange',
target: { value: 'XXX', formData: { password: 'XXX' } },
})
expect(redactSignalData(signal)).toEqual(expected)
})

it('should redact attributes in change and in target if the listener is "mutation"', () => {
const signal = factories.createInteractionSignal({
eventType: 'change',
change: { 'aria-selected': 'value' },
listener: 'mutation',
target: {
attributes: { 'aria-selected': 'value', foo: 'some other value' },
textContent: 'secret',
innerText: 'secret',
},
})
const expected = factories.createInteractionSignal({
eventType: 'change',
change: { 'aria-selected': 'XXX' },
listener: 'mutation',
target: {
attributes: { 'aria-selected': 'XXX', foo: 'XXX' },
textContent: 'XXX',
innerText: 'XXX',
},
})
expect(redactSignalData(signal)).toEqual(expected)
})

it('should redact the textContent and innerText in the "target" property if the listener is "contenteditable"', () => {
const signal = factories.createInteractionSignal({
eventType: 'change',
listener: 'contenteditable',
change: { textContent: 'secret' },
target: { textContent: 'secret', innerText: 'secret' },
})
const expected = factories.createInteractionSignal({
eventType: 'change',
listener: 'contenteditable',
change: { textContent: 'XXX' },
target: { textContent: 'XXX', innerText: 'XXX' },
})
expect(redactSignalData(signal)).toEqual(expected)
})

it('should redact the values in the "data" property if the type is "network"', () => {
const signal = factories.createNetworkSignal(
{
Expand Down
Loading

0 comments on commit 9041c59

Please sign in to comment.