Skip to content

Commit 4754f42

Browse files
committedJan 10, 2023
feat(src): add exec/execFixture support via Node's VM module
1 parent 7c51fb8 commit 4754f42

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed
 

‎src/plugin-tester.ts

+58-43
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { EOL } from 'node:os';
66
import { isNativeError } from 'node:util/types';
77
import mergeWith from 'lodash.mergewith';
88
import stripIndent from 'strip-indent';
9+
import { createContext, Script } from 'node:vm';
910

1011
import { $type } from './symbols';
1112

@@ -887,54 +888,28 @@ export function pluginTester(options: PluginTesterOptions = {}) {
887888
}
888889
})();
889890

890-
const formatResultFilepath = codeFixture || execFixture || filepath;
891-
892-
// ? We split rawBabelOutput and result into two steps to ensure exceptions
893-
// ? thrown by trimAndFixLineEndings and formatResult are not erroneously
894-
// ? captured when we only really care about errors thrown by babel
895-
const result =
896-
!errored && typeof rawBabelOutput == 'string'
897-
? trimAndFixLineEndings(
898-
formatResult(rawBabelOutput || '', {
899-
cwd: formatResultFilepath ? path.dirname(formatResultFilepath) : undefined,
900-
filepath: formatResultFilepath,
901-
filename: formatResultFilepath
902-
}),
903-
endOfLine,
904-
code
905-
)
906-
: rawBabelOutput;
907-
908891
assert(!expectedError || errored, 'expected babel to throw an error, but it did not');
909892

910-
if (exec !== undefined) {
911-
// TODO: implement run in context via node vm
912-
} else if (testConfig[$type] == 'test-object' && testConfig.snapshot) {
913-
assert(
914-
result !== code,
915-
'code was unmodified but attempted to take a snapshot. If the code should not be modified, set `snapshot: false`'
916-
);
917-
918-
const separator = '\n\n ↓ ↓ ↓ ↓ ↓ ↓\n\n';
919-
const formattedOutput = [code, separator, result].join('');
920-
921-
expect(`\n${formattedOutput}\n`).toMatchSnapshot(testBlockTitle.fullString);
922-
} else if (expectedError) {
893+
if (expectedError) {
923894
if (typeof expectedError === 'function') {
924895
if (expectedError === Error || expectedError.prototype instanceof Error) {
925896
assert(
926-
result instanceof expectedError,
897+
rawBabelOutput instanceof expectedError,
927898
`expected error to be an instance of ${
928899
expectedError.name || 'the expected error'
929900
}`
930901
);
931902
} else if (
932-
(expectedError as Exclude<typeof expectedError, Class<Error>>)(result) !== true
903+
(expectedError as Exclude<typeof expectedError, Class<Error>>)(
904+
rawBabelOutput
905+
) !== true
933906
) {
934907
assert.fail('expected `throws`/`error` function to return true');
935908
}
936909
} else {
937-
const resultString = isNativeError(result) ? result.message : String(result);
910+
const resultString = isNativeError(rawBabelOutput)
911+
? rawBabelOutput.message
912+
: String(rawBabelOutput);
938913

939914
if (typeof expectedError === 'string') {
940915
assert(
@@ -946,11 +921,54 @@ export function pluginTester(options: PluginTesterOptions = {}) {
946921
expectedError.test(resultString),
947922
`expected "${resultString}" to match ${expectedError}`
948923
);
949-
} // ? Else condition is handled in the assert above
924+
} // ? Else condition is handled by the typeof === 'function' branch
950925
}
951-
} else if (typeof result !== 'string') {
952-
throw new TypeError(`unexpected result type "${typeof result}" (excepted string)`);
953-
} else if (typeof output === 'string') {
926+
} else if (typeof rawBabelOutput !== 'string') {
927+
throw new TypeError(
928+
`unexpected babel output type "${typeof rawBabelOutput}" (excepted string)`
929+
);
930+
} else {
931+
const formatResultFilepath = codeFixture || execFixture || filepath;
932+
933+
// ? We split rawBabelOutput and result into two steps to ensure
934+
// ? exceptions thrown by trimAndFixLineEndings and formatResult are not
935+
// ? erroneously captured when we only really care about errors thrown by
936+
// ? babel
937+
const result = trimAndFixLineEndings(
938+
formatResult(rawBabelOutput || '', {
939+
cwd: formatResultFilepath ? path.dirname(formatResultFilepath) : undefined,
940+
filepath: formatResultFilepath,
941+
filename: formatResultFilepath
942+
}),
943+
endOfLine,
944+
code
945+
);
946+
947+
if (exec !== undefined) {
948+
const fakeModule = { exports: {} };
949+
const context = createContext({
950+
...globalThis,
951+
module: fakeModule,
952+
exports: fakeModule.exports,
953+
require
954+
});
955+
956+
new Script(result, { filename: execFixture }).runInContext(context, {
957+
displayErrors: true,
958+
breakOnSigint: true,
959+
microtaskMode: 'afterEvaluate'
960+
});
961+
} else if (testConfig[$type] == 'test-object' && testConfig.snapshot) {
962+
assert(
963+
result !== code,
964+
'code was unmodified but attempted to take a snapshot. If the code should not be modified, set `snapshot: false`'
965+
);
966+
967+
const separator = '\n\n ↓ ↓ ↓ ↓ ↓ ↓\n\n';
968+
const formattedOutput = [code, separator, result].join('');
969+
970+
expect(`\n${formattedOutput}\n`).toMatchSnapshot(testBlockTitle.fullString);
971+
} else if (output !== undefined) {
954972
assert.equal(
955973
result,
956974
output,
@@ -960,18 +978,15 @@ export function pluginTester(options: PluginTesterOptions = {}) {
960978
: 'expected output'
961979
}`
962980
);
963-
} else if (
964-
testConfig[$type] == 'fixture-object' &&
965-
outputFixture &&
966-
output === undefined
967-
) {
981+
} else if (testConfig[$type] == 'fixture-object' && outputFixture) {
968982
fs.writeFileSync(outputFixture, result);
969983
} else {
970984
assert.equal(
971985
result,
972986
trimAndFixLineEndings(code, endOfLine),
973987
'expected output to not change, but it did'
974988
);
989+
}
975990
}
976991
}
977992

0 commit comments

Comments
 (0)
Please sign in to comment.