Skip to content
Open
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
30 changes: 30 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function integration({ nativeShadow }) {
moduleNameMapper: {
'^smoke/(.+)$': '<rootDir>/src/modules/smoke/$1/$1',
'^(components)/(.+)$': '<rootDir>/src/modules/$1/$2/$2',
'^(logging)/(.+)$': '<rootDir>/src/modules/$1/$2/$2',
},

globals: {
Expand All @@ -44,12 +45,41 @@ function integration({ nativeShadow }) {
};
}

function logging({ nativeShadow, loggingFormatter }) {
return {
displayName: {
name: `logging formatter (${loggingFormatter ? 'enabled' : 'disabled'} feature)(${
nativeShadow ? 'native' : 'synthetic'
} shadow)`,
color: loggingFormatter ? 'yellow' : 'yellowBright',
},

rootDir: '<rootDir>/test',
preset: '@lwc/jest-preset',
testMatch: ['**/logging/*/__tests__/**/?(*.)(test).js'],
moduleNameMapper: {
'^(logging)/(.+)$': '<rootDir>/src/modules/$1/$2/$2',
},

globals: {
'lwc-jest': {
nativeShadow,
loggingFormatter,
},
},
};
}

module.exports = {
projects: [
unitTest({ nativeShadow: false }),
unitTest({ nativeShadow: true }),
integration({ nativeShadow: false }),
integration({ nativeShadow: true }),
logging({ nativeShadow: false, loggingFormatter: false }),
logging({ nativeShadow: false, loggingFormatter: true }),
logging({ nativeShadow: true, loggingFormatter: false }),
logging({ nativeShadow: true, loggingFormatter: true }),
{
displayName: {
name: `integration (ssr)`,
Expand Down
16 changes: 16 additions & 0 deletions packages/@lwc/jest-preset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ By default, this preset is configured to run the tests with synthetic shadow DOM
}
```

##### loggingFormatter (default=false)

LWC profixies any objects passed as an attribute, in events, etc...
Meaning when we use the [Console api](https://developer.mozilla.org/en-US/docs/Web/API/console), any LWC profixied objects will appear as empty.
You could enable this feature to display gracefully:

```json
{
"globals": {
"lwc-jest": {
"loggingFormatter": true
}
}
}
```

#### LWC components rendered on the Server

Add the `@lwc/jest-preset/ssr` preset to the Jest configuration like so:
Expand Down
16 changes: 16 additions & 0 deletions packages/@lwc/jest-preset/src/console.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { unwrap } = require('@lwc/engine-dom');

const originalConsole = global.console;
const augmentedConsole = {
...global.console,
};

['log', 'info', 'err', 'dir', 'warn', 'debug'].forEach((methodName) => {
augmentedConsole[methodName] = (...args) => {
originalConsole[methodName].apply(originalConsole, [
...Array.from(args).map((obj) => unwrap(obj)),
]);
};
});

global.console = augmentedConsole;
6 changes: 5 additions & 1 deletion packages/@lwc/jest-preset/src/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require('./aria-reflection-polyfill');

const config = global['lwc-jest'] || {};
const { nativeShadow } = config;
const { nativeShadow, loggingFormatter } = config;

if (!nativeShadow) {
if (
Expand All @@ -18,6 +18,10 @@ if (!nativeShadow) {
require('@lwc/synthetic-shadow');
}

if (loggingFormatter) {
require('./console');
}

// Provides temporary backward compatibility for wire-protocol reform: lwc > 1.5.0
global.wireAdaptersRegistryHack = new Map();
let originalRegisterDecorators;
Expand Down
78 changes: 78 additions & 0 deletions test/src/modules/logging/basic/__tests__/basic.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2025, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import { describe, it, test, expect, jest, afterEach } from '@jest/globals';
import { createElement } from 'lwc';
import Basic from 'logging/basic';

const featureEnabled = global['lwc-jest']?.loggingFormatter ? test : test.skip;
const featureDisabled = global['lwc-jest']?.loggingFormatter ? test.skip : test;

function prepare() {
if (console._buffer) {
// From https://github.com/jestjs/jest/blob/main/packages/jest-console/src/BufferedConsole.ts
console._buffer.length = 0;
}

if (console._stdout) {
jest.spyOn(console._stdout, 'write'); // From https://github.com/jestjs/jest/blob/main/packages/jest-console/src/CustomConsole.ts
}
}

function getLastLog() {
if (console._buffer) {
return console._buffer[0]?.message;
}

return console._stdout.write.mock.calls[1][0];
}

describe('@lwc/jest-reset - logging', () => {
afterEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});

it('renders the basic component', () => {
// Arrange
const sut = createElement('x-basic', { is: Basic });
sut.arr = ['a', { b: 5 }];

// Act
document.body.appendChild(sut);

// Assert
expect(document.body.querySelector('x-basic')).toBeInstanceOf(HTMLElement);
});

featureDisabled('the logs should be displayed but not gracefully', () => {
// Arrange
prepare();

const sut = createElement('x-basic', { is: Basic });
sut.arr = ['a', { b: 5 }];

// Act
document.body.appendChild(sut);

// Assert
expect(getLastLog().includes('Received arr: []')).toBeTruthy();
});

featureEnabled('the logs should be displayed gracefully', () => {
// Arrange
prepare();

const sut = createElement('x-basic', { is: Basic });
sut.arr = ['a', { b: 5 }];

// Act
document.body.appendChild(sut);

// Assert
expect(getLastLog().includes(`Received arr: [ 'a', { b: 5 } ]`)).toBeTruthy();
});
});
9 changes: 9 additions & 0 deletions test/src/modules/logging/basic/basic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!--
Copyright (c) 2025, salesforce.com, inc.
All rights reserved.
SPDX-License-Identifier: MIT
For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
-->
<template>
<pre><code>{plainString}</code></pre>
</template>
25 changes: 25 additions & 0 deletions test/src/modules/logging/basic/basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2025, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import { LightningElement, api } from 'lwc';

export default class Basic extends LightningElement {
_arr = [];

@api
set arr(arr) {
console.info('Received arr:', arr);
this._arr = arr;
}

get arr() {
return this._arr;
}

get plainString() {
return JSON.stringify(this.arr);
}
}