@@ -39,7 +39,10 @@ const {
3939const { DD_HOST_CPU_COUNT } = require ( '../../packages/dd-trace/src/plugins/util/env' )
4040const { ERROR_MESSAGE , ERROR_TYPE , COMPONENT } = require ( '../../packages/dd-trace/src/constants' )
4141const { DD_MAJOR , NODE_MAJOR } = require ( '../../version' )
42- const { resolveSourceLineForTest } = require ( '../../packages/datadog-plugin-cypress/src/source-map-utils' )
42+ const {
43+ resolveOriginalSourceFile,
44+ resolveSourceLineForTest,
45+ } = require ( '../../packages/datadog-plugin-cypress/src/source-map-utils' )
4346
4447const RECEIVER_STOP_TIMEOUT = 20000
4548const version = process . env . CYPRESS_VERSION
@@ -59,6 +62,30 @@ function compilePrecompiledTypeScriptSpecs (cwd, env) {
5962 }
6063}
6164
65+ /**
66+ * @param {string } cwd
67+ * @returns {void }
68+ */
69+ function configureCypressTypeScriptCompilation ( cwd ) {
70+ // Cypress's webpack preprocessor resolves TypeScript config from the spec directory.
71+ const tsconfig = {
72+ compilerOptions : {
73+ rootDir : '.' ,
74+ target : 'ES2020' ,
75+ module : 'commonjs' ,
76+ sourceMap : true ,
77+ skipLibCheck : true ,
78+ } ,
79+ }
80+
81+ const typescriptVersion = require ( path . join ( cwd , 'node_modules/typescript/package.json' ) ) . version
82+ if ( semver . gte ( typescriptVersion , '6.0.0' ) ) {
83+ tsconfig . compilerOptions . ignoreDeprecations = '6.0'
84+ }
85+
86+ fs . writeFileSync ( path . join ( cwd , 'cypress/e2e/tsconfig.json' ) , JSON . stringify ( tsconfig , null , 2 ) )
87+ }
88+
6289function shouldTestsRun ( type ) {
6390 if ( DD_MAJOR === 5 ) {
6491 if ( NODE_MAJOR <= 16 ) {
@@ -119,10 +146,7 @@ moduleTypes.forEach(({
119146
120147 // cypress-fail-fast is required as an incompatible plugin.
121148 // typescript is required to compile .cy.ts spec files in the pre-compiled JS tests.
122- // typescript@5 is pinned because typescript@6 emits "use strict" on line 1 for
123- // non-module files, shifting compiled line numbers and breaking source map resolution.
124- // TODO: Update tests files accordingly and test with different TS versions
125- useSandbox ( [ `cypress@${ version } ` , 'cypress-fail-fast@7.1.0' , 'typescript@5' ] , true )
149+ useSandbox ( [ `cypress@${ version } ` , 'cypress-fail-fast@7.1.0' , 'typescript' ] , true )
126150
127151 before ( async function ( ) {
128152 // Note: Cypress binary is already installed during useSandbox() via the postinstall script
@@ -676,6 +700,7 @@ moduleTypes.forEach(({
676700 )
677701
678702 over10It ( 'reports tests with a TypeScript config file' , async ( ) => {
703+ let testOutput = ''
679704 const receiverPromise = receiver
680705 . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
681706 const events = payloads
@@ -690,7 +715,13 @@ moduleTypes.forEach(({
690715 [ TEST_STATUS ] : 'pass' ,
691716 [ TEST_FRAMEWORK ] : 'cypress' ,
692717 } ,
693- } )
718+ } , `got events: ${ JSON . stringify ( events . map ( event => ( {
719+ resource : event . content . resource ,
720+ sourceFile : event . content . meta ?. [ TEST_SOURCE_FILE ] ,
721+ status : event . content . meta ?. [ TEST_STATUS ] ,
722+ framework : event . content . meta ?. [ TEST_FRAMEWORK ] ,
723+ error : event . content . meta ?. [ ERROR_MESSAGE ] ,
724+ } ) ) , null , 2 ) } \nCypress output:\n${ testOutput } `)
694725 } , 20000 )
695726
696727 const envVars = getCiVisAgentlessConfig ( receiver . port )
@@ -706,6 +737,12 @@ moduleTypes.forEach(({
706737 } ,
707738 }
708739 )
740+ childProcess . stdout ?. on ( 'data' , chunk => {
741+ testOutput += chunk . toString ( )
742+ } )
743+ childProcess . stderr ?. on ( 'data' , chunk => {
744+ testOutput += chunk . toString ( )
745+ } )
709746
710747 const [ [ exitCode ] ] = await Promise . all ( [
711748 once ( childProcess , 'exit' ) ,
@@ -1294,6 +1331,33 @@ moduleTypes.forEach(({
12941331 }
12951332 } )
12961333
1334+ over12It ( 'resolves source file when generated first line is unmapped' , ( ) => {
1335+ const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'dd-cypress-source-map-' ) )
1336+ const compiledFilePath = path . join ( tempDir , 'spec-prologue.js' )
1337+ const sourceMapPath = `${ compiledFilePath } .map`
1338+
1339+ try {
1340+ fs . writeFileSync ( compiledFilePath , [
1341+ '"use strict";' ,
1342+ 'it("source mapped title", () => {})' ,
1343+ '' ,
1344+ ] . join ( '\n' ) )
1345+
1346+ fs . writeFileSync ( sourceMapPath , JSON . stringify ( {
1347+ version : 3 ,
1348+ file : 'spec-prologue.js' ,
1349+ sourceRoot : '' ,
1350+ sources : [ 'spec-prologue.ts' ] ,
1351+ names : [ ] ,
1352+ mappings : ';AAEA' ,
1353+ } ) )
1354+
1355+ assert . strictEqual ( resolveOriginalSourceFile ( compiledFilePath ) , path . join ( tempDir , 'spec-prologue.ts' ) )
1356+ } finally {
1357+ fs . rmSync ( tempDir , { recursive : true , force : true } )
1358+ }
1359+ } )
1360+
12971361 over12It ( 'uses declaration scanning fallback when invocationDetails line is invalid' , async function ( ) {
12981362 const envVars = getCiVisAgentlessConfig ( receiver . port )
12991363
@@ -1429,6 +1493,8 @@ moduleTypes.forEach(({
14291493 over12It ( 'reports correct source file and line for typescript test files compiled by cypress' , async function ( ) {
14301494 // Remove any pre-compiled dist files to ensure Cypress compiles the .ts file itself
14311495 cleanupPrecompiledSourceLineDist ( cwd )
1496+ configureCypressTypeScriptCompilation ( cwd )
1497+ let testOutput = ''
14321498
14331499 const receiverPromise = receiver
14341500 . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
@@ -1438,7 +1504,18 @@ moduleTypes.forEach(({
14381504 event . content . resource . includes ( 'spec source line' )
14391505 )
14401506
1441- assert . strictEqual ( tsTestEvents . length , 2 , 'should have two typescript test events' )
1507+ assert . strictEqual (
1508+ tsTestEvents . length ,
1509+ 2 ,
1510+ `should have two typescript test events, got events: ${ JSON . stringify ( events . map ( event => ( {
1511+ type : event . type ,
1512+ resource : event . content . resource ,
1513+ sourceFile : event . content . meta ?. [ TEST_SOURCE_FILE ] ,
1514+ sourceStart : event . content . metrics ?. [ TEST_SOURCE_START ] ,
1515+ status : event . content . meta ?. [ TEST_STATUS ] ,
1516+ error : event . content . meta ?. [ ERROR_MESSAGE ] ,
1517+ } ) ) , null , 2 ) } \nCypress output:\n${ testOutput } `
1518+ )
14421519
14431520 const itTestEvent = tsTestEvents . find ( e => e . content . resource . includes ( 'reports correct line number' ) )
14441521 const testTestEvent = tsTestEvents . find (
@@ -1482,6 +1559,12 @@ moduleTypes.forEach(({
14821559 SPEC_PATTERN : 'cypress/e2e/spec-source-line.cy.ts' ,
14831560 } ,
14841561 } )
1562+ childProcess . stdout ?. on ( 'data' , chunk => {
1563+ testOutput += chunk . toString ( )
1564+ } )
1565+ childProcess . stderr ?. on ( 'data' , chunk => {
1566+ testOutput += chunk . toString ( )
1567+ } )
14851568
14861569 const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , receiverPromise ] )
14871570 assert . strictEqual ( exitCode , 0 , 'cypress process should exit successfully' )
0 commit comments