-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
assert: add snapshot assertion #44095
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e45d3b1
assert: add assert.Snapshot
MoLow 95e5182
fixup: process.env broken
MoLow f8c945c
make name required
MoLow 617e3bc
adjust to work on windows
MoLow 2a7a5db
update docs
MoLow fb0f0f7
CR
MoLow d78f55f
CR
MoLow b06b89a
fix windows
MoLow 0123718
switch to use a flag
MoLow 441c4d5
lint
MoLow be22762
fix
MoLow 97c3db2
fix windows
MoLow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
'use strict'; | ||
|
||
const { | ||
ArrayPrototypeJoin, | ||
ArrayPrototypeMap, | ||
ArrayPrototypeSlice, | ||
RegExp, | ||
SafeMap, | ||
SafeSet, | ||
StringPrototypeSplit, | ||
StringPrototypeReplace, | ||
Symbol, | ||
} = primordials; | ||
|
||
const { codes: { ERR_ASSERT_SNAPSHOT_NOT_SUPPORTED } } = require('internal/errors'); | ||
const AssertionError = require('internal/assert/assertion_error'); | ||
const { inspect } = require('internal/util/inspect'); | ||
const { getOptionValue } = require('internal/options'); | ||
const { validateString } = require('internal/validators'); | ||
const { once } = require('events'); | ||
const { createReadStream, createWriteStream } = require('fs'); | ||
const path = require('path'); | ||
const assert = require('assert'); | ||
|
||
const kUpdateSnapshot = getOptionValue('--update-assert-snapshot'); | ||
const kInitialSnapshot = Symbol('kInitialSnapshot'); | ||
const kDefaultDelimiter = '\n#*#*#*#*#*#*#*#*#*#*#*#\n'; | ||
const kDefaultDelimiterRegex = new RegExp(kDefaultDelimiter.replaceAll('*', '\\*').replaceAll('\n', '\r?\n'), 'g'); | ||
const kKeyDelimiter = /:\r?\n/g; | ||
|
||
function getSnapshotPath() { | ||
if (process.mainModule) { | ||
const { dir, name } = path.parse(process.mainModule.filename); | ||
return path.join(dir, `${name}.snapshot`); | ||
} | ||
if (!process.argv[1]) { | ||
throw new ERR_ASSERT_SNAPSHOT_NOT_SUPPORTED(); | ||
} | ||
const { dir, name } = path.parse(process.argv[1]); | ||
return path.join(dir, `${name}.snapshot`); | ||
} | ||
|
||
function getSource() { | ||
return createReadStream(getSnapshotPath(), { encoding: 'utf8' }); | ||
} | ||
|
||
let _target; | ||
function getTarget() { | ||
_target ??= createWriteStream(getSnapshotPath(), { encoding: 'utf8' }); | ||
return _target; | ||
} | ||
|
||
function serializeName(name) { | ||
validateString(name, 'name'); | ||
return StringPrototypeReplace(`${name}`, kKeyDelimiter, '_'); | ||
} | ||
|
||
let writtenNames; | ||
let snapshotValue; | ||
let counter = 0; | ||
|
||
async function writeSnapshot({ name, value }) { | ||
const target = getTarget(); | ||
if (counter > 1) { | ||
target.write(kDefaultDelimiter); | ||
} | ||
writtenNames = writtenNames || new SafeSet(); | ||
if (writtenNames.has(name)) { | ||
throw new AssertionError({ message: `Snapshot "${name}" already used` }); | ||
} | ||
writtenNames.add(name); | ||
const drained = target.write(`${name}:\n${value}`); | ||
await drained || once(target, 'drain'); | ||
} | ||
|
||
async function getSnapshot() { | ||
if (snapshotValue !== undefined) { | ||
return snapshotValue; | ||
} | ||
if (kUpdateSnapshot) { | ||
snapshotValue = kInitialSnapshot; | ||
return kInitialSnapshot; | ||
} | ||
try { | ||
const source = getSource(); | ||
let data = ''; | ||
MoLow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for await (const line of source) { | ||
data += line; | ||
} | ||
snapshotValue = new SafeMap( | ||
ArrayPrototypeMap( | ||
StringPrototypeSplit(data, kDefaultDelimiterRegex), | ||
(item) => { | ||
const arr = StringPrototypeSplit(item, kKeyDelimiter); | ||
return [ | ||
arr[0], | ||
ArrayPrototypeJoin(ArrayPrototypeSlice(arr, 1), ':\n'), | ||
]; | ||
} | ||
)); | ||
} catch (e) { | ||
if (e.code === 'ENOENT') { | ||
snapshotValue = kInitialSnapshot; | ||
} else { | ||
throw e; | ||
} | ||
} | ||
return snapshotValue; | ||
} | ||
|
||
|
||
async function snapshot(input, name) { | ||
const snapshot = await getSnapshot(); | ||
counter = counter + 1; | ||
name = serializeName(name); | ||
|
||
const value = inspect(input); | ||
if (snapshot === kInitialSnapshot) { | ||
await writeSnapshot({ name, value }); | ||
} else if (snapshot.has(name)) { | ||
const expected = snapshot.get(name); | ||
// eslint-disable-next-line no-restricted-syntax | ||
assert.strictEqual(value, expected); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's kind of a bummer that this does string comparison and not |
||
} else { | ||
throw new AssertionError({ message: `Snapshot "${name}" does not exist`, actual: inspect(snapshot) }); | ||
} | ||
} | ||
|
||
module.exports = snapshot; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import assert from 'node:assert'; | ||
|
||
await assert.snapshot("test", "name"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import assert from 'node:assert'; | ||
|
||
await assert.snapshot("test", "name"); | ||
await assert.snapshot("test", "another name"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import assert from 'node:assert'; | ||
|
||
await assert.snapshot("test", "another name"); | ||
await assert.snapshot("test", "non existing"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
another name: | ||
'test' | ||
#*#*#*#*#*#*#*#*#*#*#*# | ||
name: | ||
'test' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import assert from 'node:assert'; | ||
|
||
function random() { | ||
return `Random Value: ${Math.random()}`; | ||
} | ||
function transform(value) { | ||
return value.replaceAll(/Random Value: \d+\.+\d+/g, 'Random Value: *'); | ||
} | ||
|
||
await assert.snapshot(transform(random()), 'random1'); | ||
await assert.snapshot(transform(random()), 'random2'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
random1: | ||
'Random Value: *' | ||
#*#*#*#*#*#*#*#*#*#*#*# | ||
random2: | ||
'Random Value: *' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import assert from 'node:assert'; | ||
|
||
function fn() { | ||
this.should.be.a.fn(); | ||
return false; | ||
} | ||
|
||
await assert.snapshot(fn, 'function'); | ||
await assert.snapshot({ foo: "bar" }, 'object'); | ||
await assert.snapshot(new Set([1, 2, 3]), 'set'); | ||
await assert.snapshot(new Map([['one', 1], ['two', 2]]), 'map'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
function: | ||
[Function: fn] | ||
#*#*#*#*#*#*#*#*#*#*#*# | ||
object: | ||
{ foo: 'bar' } | ||
#*#*#*#*#*#*#*#*#*#*#*# | ||
set: | ||
Set(3) { 1, 2, 3 } | ||
#*#*#*#*#*#*#*#*#*#*#*# | ||
map: | ||
Map(2) { 'one' => 1, 'two' => 2 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import assert from 'node:assert'; | ||
|
||
await assert.snapshot("test", "snapshot"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import assert from 'node:assert'; | ||
|
||
await assert.snapshot("changed", "snapshot"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
snapshot: | ||
'original' |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to check if we're in the REPL? wouldn't it be better to just check if there is no
process.mainModule?.filename
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
esm does not have
process.mainModule
either, soargv[1]
is used insteadThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't read the code, but reminder that
process.argv[1] == false
when doing stdin eval and--eval
, not just in REPL.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is documented to not be supported at this stage.
In a further stage we can support the source and target options that were in the original commit