Skip to content

Commit 50526a3

Browse files
authored
ref(nextjs): Small changes to nextjs integration test runner (#3819)
This makes a number of small tweaks to the integration test runner in `@sentry/nextjs`, mostly changes I made to help myself as I was trying to debug failing tests in another PR, either because they made the debugging itself easier or because they sped up the overall running of the test suite (in most cases by doing things only once instead of multiple times where possible). Included changes: - Add a default version of `nextjs` to the integration test project’s dependencies. This makes it possible to call `yarn` (and `yarn build`) out of the context of the test runner script (specifically, when using a debugger). - Add a VSCode debug profile for nextjs integration tests. - Speed up initial setup by only having `yarn` install packages once per version of `next` (instead of once to install all non-`nextjs` packages, and again when adding the specific version of `next`). - Back up `next.config.js` outside of the loops, so we’re guaranteed to restore from the original. - As part of cleanup, nuke all of `node_modules` rather than just removing `nextjs` (we’re going to delete `node_modules` before the next run anyway, and this way `yarn` doesn’t go through yet another install process on its way out the door). - Also as part of cleanup, remove all files added to the yarn cache as a result of this test run, in order to prevent the cache from growing arbitrarily large. - Only run check on node version once, since it’s the same across all loops. - Label each event/transaction/session displayed (when using `--debug` on server tests) with the name of the test it's from. - 
Remove test for tracing 404s, since it the underlying code doesn’t actually work on its own (this is okay; we don’t capture 404s in any other framework). - Make some formatting changes (as insisted upon by the auto-formatter). - Add some comments and clean up logging a little bit.
1 parent 61a22ec commit 50526a3

File tree

10 files changed

+98
-58
lines changed

10 files changed

+98
-58
lines changed

.vscode/launch.json

+23
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@
5454
"internalConsoleOptions": "neverOpen", // since we're not using it, don't automatically switch to it
5555
},
5656

57+
// @sentry/nextjs - run a specific integration test file
58+
// must have file in currently active tab when hitting the play button
59+
{
60+
"type": "node",
61+
"request": "launch",
62+
"cwd": "${workspaceFolder}/packages/nextjs",
63+
"name": "Debug @sentry/nextjs integration tests - just open file",
64+
// TODO create a build task
65+
// "preLaunchTask": "yarn build",
66+
"program": "${workspaceFolder}/packages/nextjs/test/integration/test/server.js",
67+
"args": [
68+
"--debug",
69+
// remove these two lines to run all integration tests
70+
"--filter",
71+
"${fileBasename}"
72+
],
73+
"disableOptimisticBPs": true,
74+
"sourceMaps": true,
75+
"skipFiles": [
76+
"<node_internals>/**", "**/tslib/**"
77+
],
78+
},
79+
5780
// @sentry/node - run a specific test file in watch mode
5881
// must have file in currently active tab when hitting the play button
5982
{

packages/nextjs/test/integration/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
},
99
"dependencies": {
1010
"@sentry/nextjs": "file:../../",
11+
"next": "latest",
1112
"react": "^17.0.1",
1213
"react-dom": "^17.0.1"
1314
},

packages/nextjs/test/integration/test/server/errorApiEndpoint.js

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = async ({ url, argv }) => {
2424
transaction: 'GET /api/error',
2525
},
2626
argv,
27+
'errorApiEndpoint',
2728
);
2829

2930
await getAsync(`${url}/api/error`);

packages/nextjs/test/integration/test/server/errorServerSideProps.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module.exports = async ({ url, argv }) => {
2323
},
2424
},
2525
argv,
26+
'errorServerSideProps',
2627
);
2728

2829
await getAsync(`${url}/withServerSideProps`);

packages/nextjs/test/integration/test/server/tracing200.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module.exports = async ({ url, argv }) => {
2020
},
2121
},
2222
argv,
23+
'tracing200',
2324
);
2425

2526
await getAsync(`${url}/api/users`);

packages/nextjs/test/integration/test/server/tracing404.js

-29
This file was deleted.

packages/nextjs/test/integration/test/server/tracing500.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module.exports = async ({ url, argv }) => {
2020
},
2121
},
2222
argv,
23+
'tracing500',
2324
);
2425

2526
await getAsync(`${url}/api/broken`);

packages/nextjs/test/integration/test/server/tracingHttp.js

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ module.exports = async ({ url, argv }) => {
3434
},
3535
},
3636
argv,
37+
'tracingHttp',
3738
);
3839

3940
await getAsync(`${url}/api/http`);

packages/nextjs/test/integration/test/utils/server.js

+31-7
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,57 @@ const getAsync = url => {
2121
});
2222
};
2323

24-
const interceptEventRequest = (expectedEvent, argv) => {
24+
const interceptEventRequest = (expectedEvent, argv, testName = '') => {
2525
return nock('https://dsn.ingest.sentry.io')
2626
.post('/api/1337/store/', body => {
27-
logIf(argv.debug, 'Intercepted Event', body, argv.depth);
27+
logIf(
28+
argv.debug,
29+
'\nIntercepted Event' + (testName.length ? ` (from test \`${testName}\`)` : ''),
30+
body,
31+
argv.depth,
32+
);
2833
return objectMatches(body, expectedEvent);
2934
})
3035
.reply(200);
3136
};
3237

33-
const interceptSessionRequest = (expectedItem, argv) => {
38+
const interceptSessionRequest = (expectedItem, argv, testName = '') => {
3439
return nock('https://dsn.ingest.sentry.io')
3540
.post('/api/1337/envelope/', body => {
3641
const { envelopeHeader, itemHeader, item } = parseEnvelope(body);
37-
logIf(argv.debug, 'Intercepted Transaction', { envelopeHeader, itemHeader, item }, argv.depth);
42+
logIf(
43+
argv.debug,
44+
'\nIntercepted Session' + (testName.length ? ` (from test \`${testName}\`)` : ''),
45+
{ envelopeHeader, itemHeader, item },
46+
argv.depth,
47+
);
3848
return itemHeader.type === 'session' && objectMatches(item, expectedItem);
3949
})
4050
.reply(200);
4151
};
4252

43-
const interceptTracingRequest = (expectedItem, argv) => {
53+
const interceptTracingRequest = (expectedItem, argv, testName = '') => {
4454
return nock('https://dsn.ingest.sentry.io')
4555
.post('/api/1337/envelope/', body => {
4656
const { envelopeHeader, itemHeader, item } = parseEnvelope(body);
47-
logIf(argv.debug, 'Intercepted Transaction', { envelopeHeader, itemHeader, item }, argv.depth);
57+
logIf(
58+
argv.debug,
59+
'\nIntercepted Transaction' + (testName.length ? ` (from test \`${testName}\`)` : ''),
60+
{ envelopeHeader, itemHeader, item },
61+
argv.depth,
62+
);
4863
return itemHeader.type === 'transaction' && objectMatches(item, expectedItem);
4964
})
5065
.reply(200);
5166
};
5267

68+
/**
69+
* Recursively checks that every path/value pair in `expected` matches that in `actual` (but not vice-versa).
70+
*
71+
* Only works for JSONifiable data.
72+
*/
5373
const objectMatches = (actual, expected) => {
74+
// each will output either '[object Object]' or '[object <ClassName>]'
5475
if (Object.prototype.toString.call(actual) !== Object.prototype.toString.call(expected)) {
5576
return false;
5677
}
@@ -59,11 +80,14 @@ const objectMatches = (actual, expected) => {
5980
const expectedValue = expected[key];
6081
const actualValue = actual[key];
6182

83+
// recurse
6284
if (Object.prototype.toString.call(expectedValue) === '[object Object]' || Array.isArray(expectedValue)) {
6385
if (!objectMatches(actualValue, expectedValue)) {
6486
return false;
6587
}
66-
} else {
88+
}
89+
// base case
90+
else {
6791
if (actualValue !== expectedValue) {
6892
return false;
6993
}

packages/nextjs/test/run-integration-tests.sh

+38-22
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,33 @@
22

33
set -e
44

5+
START_TIME=$(date -R)
6+
57
function cleanup {
68
echo "[nextjs] Cleaning up..."
7-
mv next.config.js.bak next.config.js 2> /dev/null || true
8-
yarn remove next > /dev/null 2>&1 || true
9+
mv next.config.js.bak next.config.js 2>/dev/null || true
10+
rm -rf node_modules 2>/dev/null || true
11+
12+
# Delete yarn's cached versions of sentry packages added during this test run, since every test run installs multiple
13+
# copies of each package. Without this, the cache can balloon in size quickly if integration tests are being run
14+
# multiple times in a row.
15+
find $(yarn cache dir) -iname "npm-@sentry*" -newermt "$START_TIME" -mindepth 1 -maxdepth 1 -exec rm -rf {} \;
16+
917
echo "[nextjs] Test run complete"
1018
}
1119

1220
trap cleanup EXIT
1321

1422
cd "$(dirname "$0")/integration"
1523

24+
NODE_VERSION=$(node -v)
25+
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -c2- | cut -d. -f1)
26+
echo "Running integration tests on Node $NODE_VERSION"
27+
28+
# make a backup of our config file so we can restore it when we're done
29+
mv next.config.js next.config.js.bak
30+
1631
for NEXTJS_VERSION in 10 11; do
17-
NODE_VERSION=$(node -v)
18-
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -c2- | cut -d. -f1)
1932

2033
# Next 10 requires at least Node v10
2134
if [ "$NODE_MAJOR" -lt "10" ]; then
@@ -25,63 +38,66 @@ for NEXTJS_VERSION in 10 11; do
2538

2639
# Next.js v11 requires at least Node v12
2740
if [ "$NODE_MAJOR" -lt "12" ] && [ "$NEXTJS_VERSION" -eq "11" ]; then
28-
echo "[nextjs$NEXTJS_VERSION] Not compatible with Node $NODE_VERSION"
41+
echo "[nextjs$NEXTJS_VERSION] Not compatible with Node $NODE_MAJOR"
2942
exit 0
3043
fi
3144

32-
echo "[nextjs@$NEXTJS_VERSION] Running integration tests on $NODE_VERSION"
33-
3445
echo "[nextjs@$NEXTJS_VERSION] Preparing environment..."
35-
mv next.config.js next.config.js.bak
36-
rm -rf node_modules .next .env.local 2> /dev/null || true
46+
rm -rf node_modules .next .env.local 2>/dev/null || true
3747

3848
echo "[nextjs@$NEXTJS_VERSION] Installing dependencies..."
39-
yarn --no-lockfile --silent > /dev/null 2>&1
40-
yarn add "next@$NEXTJS_VERSION" > /dev/null 2>&1
49+
# set the desired version of next long enough to run yarn, and then restore the old version (doing the restoration now
50+
# rather than during overall cleanup lets us look for "latest" in both loops)
51+
cp package.json package.json.bak
52+
if [[ $(uname) == "Darwin" ]]; then
53+
sed -i "" /"next.*latest"/s/latest/"${NEXTJS_VERSION}.x"/ package.json
54+
else
55+
sed -i /"next.*latest"/s/latest/"${NEXTJS_VERSION}.x"/ package.json
56+
fi
57+
yarn --no-lockfile --silent >/dev/null 2>&1
58+
mv -f package.json.bak package.json 2>/dev/null || true
4159

4260
for RUN_WEBPACK_5 in false true; do
4361
[ "$RUN_WEBPACK_5" == true ] &&
4462
WEBPACK_VERSION=5 ||
4563
WEBPACK_VERSION=4
4664

65+
# next 10 defaults to webpack 4 and next 11 defaults to webpack 5, but each can use either based on settings
4766
if [ "$NEXTJS_VERSION" -eq "10" ]; then
48-
sed "s/%RUN_WEBPACK_5%/$RUN_WEBPACK_5/g" < next10.config.template > next.config.js
67+
sed "s/%RUN_WEBPACK_5%/$RUN_WEBPACK_5/g" <next10.config.template >next.config.js
4968
else
50-
sed "s/%RUN_WEBPACK_5%/$RUN_WEBPACK_5/g" < next11.config.template > next.config.js
69+
sed "s/%RUN_WEBPACK_5%/$RUN_WEBPACK_5/g" <next11.config.template >next.config.js
5170
fi
5271

5372
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Building..."
5473
yarn build | grep "Using webpack"
5574

56-
# if no arguments were passed, default to outputting nothing other than success and failure messages ($* gets all
57-
# passed args as a single string)
5875
args=$*
5976
if [[ ! $args ]]; then
77+
# restrict each test to only output success and failure messages
6078
args="--silent"
6179
fi
6280

6381
# we keep this updated as we run the tests, so that if it's ever non-zero, we can bail
6482
EXIT_CODE=0
6583

66-
echo "Running server tests with options: $args"
84+
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Running server tests with options: $args"
6785
node test/server.js $args || EXIT_CODE=$?
6886

69-
if [ $EXIT_CODE -eq 0 ]
70-
then
87+
if [ $EXIT_CODE -eq 0 ]; then
7188
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Server integration tests passed"
7289
else
7390
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Server integration tests failed"
7491
exit 1
7592
fi
7693

77-
echo "Running client tests with options: $args"
94+
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Running client tests with options: $args"
7895
node test/client.js $args || EXIT_CODE=$?
79-
if [ $EXIT_CODE -eq 0 ]
80-
then
96+
if [ $EXIT_CODE -eq 0 ]; then
8197
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Client integration tests passed"
8298
else
8399
echo "[nextjs@$NEXTJS_VERSION | webpack@$WEBPACK_VERSION] Client integration tests failed"
84100
exit 1
85101
fi
86102
done
87-
done;
103+
done

0 commit comments

Comments
 (0)