Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/e2e-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ jobs:
- name: Create .env with environment variables to be set on the MRT target
run: |-
echo "PWA_KIT_SLAS_CLIENT_SECRET=${{ secrets.ZZRF_002_SLAS_PRIVATE_CLIENT_SECRET }}" > ${{ vars.MRT_ENV_VARS_E2E_BASE_FILENAME }}
echo "OTEL_TRACING_ENABLED=true" >> ${{ vars.MRT_ENV_VARS_E2E_BASE_FILENAME }}

# Call the e2e/scripts/update-mrt-target.js script to update the MRT target config and environment variables.
# This script is a Node.js script that makes a PATCH request to the MRT API to update the MRT target config and environment variables.
Expand Down
19 changes: 14 additions & 5 deletions e2e/scripts/validate-generated-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ const validateExtensibilityConfig = async (project, templateVersion) => {
const pkg = require(pkgPath)
return new Promise((resolve, reject) => {
if (
!pkg.hasOwn('ccExtensibility') ||
!pkg['ccExtensibility'].hasOwn('extends') ||
!pkg['ccExtensibility'].hasOwn('overridesDir') ||
!Object.hasOwn(pkg, 'ccExtensibility') ||
!Object.hasOwn(pkg['ccExtensibility'], 'extends') ||
!Object.hasOwn(pkg['ccExtensibility'], 'overridesDir') ||
pkg['ccExtensibility'].extends !== '@salesforce/retail-react-app' ||
pkg['ccExtensibility'].overridesDir !== 'overrides'
) {
Expand Down Expand Up @@ -94,6 +94,15 @@ program
)
.option('--templateVersion <templateVersion>', 'Template version used to generate the project')

program.parse(process.argv)
// Export functions for testing
module.exports = {
validateGeneratedArtifacts,
validateExtensibilityConfig,
main
}

main(program)
// Only run CLI when file is executed directly
if (require.main === module) {
program.parse(process.argv)
main(program)
}
153 changes: 153 additions & 0 deletions e2e/scripts/validate-generated-project.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright (c) 2025, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

const fs = require('fs')
const path = require('path')

// Mock the dependencies
jest.mock('fs')

// Mocking the config.js file to allow testing with smaller arrays of expected artifacts
jest.mock('../config.js', () => ({
GENERATED_PROJECTS_DIR: '../generated-projects',
EXPECTED_GENERATED_ARTIFACTS: {
'retail-app-demo': ['package.json', 'node_modules', 'config'],
'retail-app-ext': ['package.json', 'node_modules', 'overrides']
}
}))
jest.mock('./utils.js', () => ({
diffArrays: jest.fn()
}))

// Import the functions to test
const {diffArrays} = require('./utils.js')
const {validateGeneratedArtifacts} = require('./validate-generated-project.js')

describe('validateGeneratedArtifacts', () => {
beforeEach(() => {
jest.clearAllMocks()
})

test('resolves when all expected artifacts are present', async () => {
const project = 'retail-app-demo'
const expectedArtifacts = ['package.json', 'node_modules', 'config']
const actualArtifacts = ['package.json', 'node_modules', 'config', 'extra-file']

fs.readdirSync.mockReturnValue(actualArtifacts)
diffArrays.mockReturnValue([])

const result = await validateGeneratedArtifacts(project)

expect(fs.readdirSync).toHaveBeenCalledWith(
// path.sep is used to handle the platform-specific path separator. (Windows uses \ and other platforms use /)
expect.stringContaining(`generated-projects${path.sep}${project}`)
)
expect(diffArrays).toHaveBeenCalledWith(expectedArtifacts, actualArtifacts)
expect(result).toBe(`Successfully validated generated artifacts for: ${project} `)
})

test('rejects when artifacts are missing', async () => {
const project = 'retail-app-demo'
const actualArtifacts = ['package.json', 'node_modules']
const missingArtifacts = ['config']

fs.readdirSync.mockReturnValue(actualArtifacts)
diffArrays.mockReturnValue(missingArtifacts)

await expect(validateGeneratedArtifacts(project)).rejects.toBe(
`Generated project (${project}) is missing one or more artifacts: ${missingArtifacts}`
)
})

test('rejects when project directory does not exist', async () => {
const project = 'non-existent-project'
const error = new Error('ENOENT: no such file or directory')

fs.readdirSync.mockImplementation(() => {
throw error
})

await expect(validateGeneratedArtifacts(project)).rejects.toBe(
`Generated project (${project}) is missing one or more artifacts: ${error}`
)
})

test('handles project with no expected artifacts', async () => {
const project = 'unknown-project'
const actualArtifacts = ['some-file']

fs.readdirSync.mockReturnValue(actualArtifacts)
diffArrays.mockReturnValue([])

const result = await validateGeneratedArtifacts(project)

expect(diffArrays).toHaveBeenCalledWith([], actualArtifacts)
expect(result).toBe(`Successfully validated generated artifacts for: ${project} `)
})
})

// Since it requires files at runtime, we'll test the key validation logic
describe('validateExtensibilityConfig validation logic', () => {
test('validates Object.hasOwn usage for extensibility config', () => {
// Test the core validation logic that was fixed
const validConfig = {
ccExtensibility: {
extends: '@salesforce/retail-react-app',
overridesDir: 'overrides'
}
}

const invalidConfigMissingProperty = {
ccExtensibility: {
extends: '@salesforce/retail-react-app'
// missing overridesDir
}
}

const invalidConfigWrongExtends = {
ccExtensibility: {
extends: '@wrong/package',
overridesDir: 'overrides'
}
}

expect(Object.hasOwn(validConfig, 'ccExtensibility')).toBe(true)
expect(Object.hasOwn(validConfig.ccExtensibility, 'extends')).toBe(true)
expect(Object.hasOwn(validConfig.ccExtensibility, 'overridesDir')).toBe(true)

expect(Object.hasOwn(invalidConfigMissingProperty.ccExtensibility, 'overridesDir')).toBe(
false
)

const isValidConfig = (pkg) => {
return (
Object.hasOwn(pkg, 'ccExtensibility') &&
Object.hasOwn(pkg.ccExtensibility, 'extends') &&
Object.hasOwn(pkg.ccExtensibility, 'overridesDir') &&
pkg.ccExtensibility.extends === '@salesforce/retail-react-app' &&
pkg.ccExtensibility.overridesDir === 'overrides'
)
}

expect(isValidConfig(validConfig)).toBe(true)
expect(isValidConfig(invalidConfigMissingProperty)).toBe(false)
expect(isValidConfig(invalidConfigWrongExtends)).toBe(false)
})

test('validates template version matching logic', () => {
const pkg = {version: '1.0.0'}

const validateVersion = (pkg, templateVersion) => {
return !templateVersion || pkg.version === templateVersion
}

expect(validateVersion(pkg, undefined)).toBe(true)
expect(validateVersion(pkg, null)).toBe(true)
expect(validateVersion(pkg, '1.0.0')).toBe(true)
expect(validateVersion(pkg, '2.0.0')).toBe(false)
})
})
2 changes: 1 addition & 1 deletion e2e/tests/opentelemetry-b3-tracing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test.beforeEach(async ({page}) => {
})
})

test.skip('should inject B3 headers when __server_timing param is passed', async ({page}) => {
test('should inject B3 headers when __server_timing param is passed', async ({page}) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.. once we enable OTEL, then this test should pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set the env var in the workflow to enable OTEL so the test should pass.

const url = `${config.RETAIL_APP_HOME}?__server_timing=true`

const responseHeaders = []
Expand Down
Loading