-
Notifications
You must be signed in to change notification settings - Fork 35
Only allow enablePrivateMethod to be true for lightning & interop namespaces #420
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
Merged
a-chabot
merged 17 commits into
salesforce:master
from
a-chabot:a-chabot/add-private-methods-flag
Apr 15, 2026
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
595dcdc
Add enablePrivateMethods compiler option to jest-transformer
a-chabot 1d0669e
Bump LWC to 9.1.0 and add private methods integration tests
a-chabot cc90019
Fix yarn.lock to use public npm registry instead of internal proxy
a-chabot 0cfeade
feat: extractNamespace
a-chabot b638e8d
feat: tests
a-chabot fbcd722
fix: add tests
a-chabot 2845c50
Merge branch 'master' of upstream into a-chabot/add-private-methods-flag
a-chabot ce8cfb6
fix: always x
a-chabot d3ba05e
fix: missed test
a-chabot a50cb88
fix: missed test
a-chabot 1d69932
fix: test
a-chabot 8385acf
fix: smoke-private-methods
a-chabot 637add0
fix: relateive and absolute paths
a-chabot 815c81b
fix: new module
a-chabot 2d286ad
fix: clean up tests
a-chabot ef0a6ad
fix: no fallback x
a-chabot 3723689
fix: basic test
a-chabot 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 hidden or 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
48 changes: 48 additions & 0 deletions
48
packages/@lwc/jest-transformer/src/__tests__/extract-namespace.test.js
This file contains hidden or 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,48 @@ | ||
| const { extractNamespace } = require('../extract-namespace'); | ||
|
|
||
| describe('extractNamespace', () => { | ||
| it("returns '' when path does not match modules/ or jest-modules/ layout", () => { | ||
| expect(extractNamespace('/repo/src/foo.js')).toBe(''); | ||
| }); | ||
|
|
||
| it('returns the namespace segment when path is /modules/{namespace}/...', () => { | ||
| expect(extractNamespace('/modules/x/foo/bar.js')).toBe('x'); | ||
| expect(extractNamespace('/modules/x/foo/bar/baz.js')).toBe('x'); | ||
| expect(extractNamespace('/modules/lightning/spinner/spinner.js')).toBe('lightning'); | ||
| expect(extractNamespace('/modules/interop/spinner/spinner.js')).toBe('interop'); | ||
| }); | ||
|
|
||
| it('returns namespace from modules/{namespace}/...', () => { | ||
| expect(extractNamespace('/repo/modules/c/foo/foo.js')).toBe('c'); | ||
| }); | ||
|
|
||
| it('returns namespace when path contains __tests__', () => { | ||
| expect(extractNamespace('/repo/modules/c/foo/__tests__/foo.test.js')).toBe('c'); | ||
| }); | ||
|
|
||
| it('returns namespace from jest-modules/{namespace}/...', () => { | ||
| expect(extractNamespace('/repo/jest-modules/interop/bar/bar.js')).toBe('interop'); | ||
| }); | ||
|
|
||
| it('normalizes Windows separators before matching', () => { | ||
| expect(extractNamespace('C:\\repo\\modules\\lightning\\x\\x.js')).toBe('lightning'); | ||
| }); | ||
|
|
||
| it('extracts namespace from absolute paths', () => { | ||
| expect(extractNamespace('/var/project/modules/lightning/button/button.js')).toBe( | ||
| 'lightning' | ||
| ); | ||
| expect(extractNamespace('/repo/nested/jest-modules/interop/cmp/cmp.js')).toBe('interop'); | ||
| }); | ||
|
|
||
| it('extracts namespace from relative paths', () => { | ||
| expect(extractNamespace('project/modules/smoke/widget/widget.js')).toBe('smoke'); | ||
| expect(extractNamespace('modules/c/foo/foo.js')).toBe('c'); | ||
| expect(extractNamespace('./src/jest-modules/interop/x/x.js')).toBe('interop'); | ||
| expect(extractNamespace('packages/pkg/modules/custom/lib/lib.js')).toBe('custom'); | ||
| }); | ||
|
|
||
| it("returns '' when modules segment has no trailing path segment", () => { | ||
| expect(extractNamespace('/repo/modules')).toBe(''); | ||
| }); | ||
| }); | ||
99 changes: 99 additions & 0 deletions
99
packages/@lwc/jest-transformer/src/__tests__/transform-lwc-options.test.js
This file contains hidden or 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,99 @@ | ||
| /* | ||
| * Copyright (c) 2018, 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 | ||
| */ | ||
| jest.mock('@lwc/compiler/dist/index.cjs', () => ({ | ||
| transformSync: jest.fn(() => ({ | ||
| code: '/* lwc-compiled */', | ||
| map: null, | ||
| warnings: [], | ||
| })), | ||
| })); | ||
|
|
||
| jest.mock('@babel/core', () => ({ | ||
| transform: jest.fn(() => ({ code: '/* babel */' })), | ||
| })); | ||
|
|
||
| jest.mock('@lwc/template-compiler/dist/index.cjs', () => ({ | ||
| generateScopeTokens: jest.fn(() => ({ cssScopeTokens: undefined })), | ||
| })); | ||
|
|
||
| const lwcCompiler = require('@lwc/compiler/dist/index.cjs'); | ||
| const { transformLwc } = require('../index'); | ||
|
|
||
| describe('transformLwc compiler options (namespace / enablePrivateMethods)', () => { | ||
| beforeEach(() => { | ||
| jest.clearAllMocks(); | ||
| }); | ||
|
|
||
| it('sets enablePrivateMethods true when path matches modules/... (lightning)', () => { | ||
| transformLwc('export default class {}', '/repo/modules/lightning/foo/foo.js', false); | ||
|
|
||
| expect(lwcCompiler.transformSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| '/repo/modules/lightning/foo/foo.js', | ||
| expect.objectContaining({ | ||
| namespace: 'x', | ||
| enablePrivateMethods: true, | ||
| }) | ||
| ); | ||
| }); | ||
|
|
||
| it('sets enablePrivateMethods true when path matches modules/... (interop)', () => { | ||
| transformLwc('export default class {}', '/repo/modules/interop/bar/bar.js', false); | ||
|
|
||
| expect(lwcCompiler.transformSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| '/repo/modules/interop/bar/bar.js', | ||
| expect.objectContaining({ | ||
| namespace: 'x', | ||
| enablePrivateMethods: true, | ||
| }) | ||
| ); | ||
| }); | ||
|
|
||
| it('sets enablePrivateMethods false when path matches modules/smoke/...', () => { | ||
| transformLwc( | ||
| 'export default class {}', | ||
| '/repo/modules/smoke/privateMethods/privateMethods.js', | ||
| false | ||
| ); | ||
|
|
||
| expect(lwcCompiler.transformSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| '/repo/modules/smoke/privateMethods/privateMethods.js', | ||
| expect.objectContaining({ | ||
| namespace: 'x', | ||
| enablePrivateMethods: false, | ||
| }) | ||
| ); | ||
| }); | ||
|
|
||
| it('sets enablePrivateMethods false for other modules/... namespaces', () => { | ||
| transformLwc('export default class {}', '/repo/modules/c/baz/baz.js', false); | ||
|
|
||
| expect(lwcCompiler.transformSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| '/repo/modules/c/baz/baz.js', | ||
| expect.objectContaining({ | ||
| namespace: 'x', | ||
| enablePrivateMethods: false, | ||
| }) | ||
| ); | ||
| }); | ||
|
|
||
| it('sets enablePrivateMethods false when path has no modules/ or jest-modules/ segment', () => { | ||
| transformLwc('export default class {}', '/repo/src/standalone.js', false); | ||
|
|
||
| expect(lwcCompiler.transformSync).toHaveBeenCalledWith( | ||
| expect.any(String), | ||
| '/repo/src/standalone.js', | ||
| expect.objectContaining({ | ||
| namespace: 'x', | ||
| enablePrivateMethods: false, | ||
| }) | ||
| ); | ||
| }); | ||
| }); |
This file contains hidden or 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,31 @@ | ||
| /* | ||
| * Copyright (c) 2018, 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 | ||
| */ | ||
|
|
||
| /** | ||
| * Extracts the namespace from file path | ||
| * Handles patterns like: | ||
| * - modules/{namespace}/{component}/{component}.js | ||
| * - modules/{namespace}/{component}/__tests__/... | ||
| * - jest-modules/{namespace}/{component}/{component}.js | ||
| * Returns '' if the namespace cannot be determined | ||
| * @param {string} filePath | ||
| * @returns {string} | ||
| */ | ||
| function extractNamespace(filePath) { | ||
| const normalizedPath = filePath.replace(/\\/g, '/'); | ||
|
|
||
| // Match patterns: modules/{namespace} or jest-modules/{namespace} | ||
| const match = normalizedPath.match(/(?:^|\/)(modules|jest-modules)\/([^/]+)\//); | ||
|
|
||
| if (match && match[2]) { | ||
| return match[2]; | ||
| } | ||
|
|
||
| return ''; | ||
| } | ||
|
|
||
| module.exports = { extractNamespace }; |
This file contains hidden or 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
31 changes: 31 additions & 0 deletions
31
test/src/modules/lightning/privateMethods/__tests__/privateMethods.test.js
This file contains hidden or 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,31 @@ | ||
| /* | ||
| * Copyright (c) 2018, 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 { createElement } from 'lwc'; | ||
| import PrivateMethods from '../privateMethods'; | ||
|
|
||
| describe('lightning private methods', () => { | ||
| it('should allow calling private methods from public methods', () => { | ||
| const element = createElement('lightning-private-methods', { is: PrivateMethods }); | ||
|
Contributor
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. Can we test both
Collaborator
Author
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. sure! |
||
| document.body.appendChild(element); | ||
|
|
||
| expect(element.publicMethod()).toBe(1); | ||
| expect(element.value).toBe(1); | ||
| expect(element.getCounter()).toBe(1); | ||
| }); | ||
|
|
||
| it('should maintain state across multiple calls', () => { | ||
| const element = createElement('lightning-private-methods', { is: PrivateMethods }); | ||
| document.body.appendChild(element); | ||
|
|
||
| element.publicMethod(); | ||
| element.publicMethod(); | ||
| const result = element.publicMethod(); | ||
|
|
||
| expect(result).toBe(3); | ||
| expect(element.getCounter()).toBe(3); | ||
| }); | ||
| }); | ||
30 changes: 30 additions & 0 deletions
30
test/src/modules/lightning/privateMethods/privateMethods.js
This file contains hidden or 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,30 @@ | ||
| /* | ||
| * Copyright (c) 2018, 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 PrivateMethods extends LightningElement { | ||
| @api value = 0; | ||
| counter = 0; | ||
|
|
||
| #incrementPrivate() { | ||
| this.counter++; | ||
| return this.counter; | ||
| } | ||
|
|
||
| @api | ||
| publicMethod() { | ||
| // Call private method from public method | ||
| const count = this.#incrementPrivate(); | ||
| this.value = count; | ||
| return count; | ||
| } | ||
|
|
||
| @api | ||
| getCounter() { | ||
| return this.counter; | ||
| } | ||
| } |
37 changes: 8 additions & 29 deletions
37
test/src/modules/smoke/privateMethods/__tests__/privateMethods.test.js
This file contains hidden or 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 |
|---|---|---|
| @@ -1,31 +1,10 @@ | ||
| /* | ||
| * Copyright (c) 2018, 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 { createElement } from 'lwc'; | ||
| import PrivateMethods from '../privateMethods'; | ||
|
|
||
| describe('private methods', () => { | ||
| it('should allow calling private methods from public methods', () => { | ||
| const element = createElement('smoke-private-methods', { is: PrivateMethods }); | ||
| document.body.appendChild(element); | ||
|
|
||
| expect(element.publicMethod()).toBe(1); | ||
| expect(element.value).toBe(1); | ||
| expect(element.getCounter()).toBe(1); | ||
| }); | ||
|
|
||
| it('should maintain state across multiple calls', () => { | ||
| const element = createElement('smoke-private-methods', { is: PrivateMethods }); | ||
| document.body.appendChild(element); | ||
|
|
||
| element.publicMethod(); | ||
| element.publicMethod(); | ||
| const result = element.publicMethod(); | ||
|
|
||
| expect(result).toBe(3); | ||
| expect(element.getCounter()).toBe(3); | ||
| describe('smoke private methods (smoke-private-methods)', () => { | ||
| // A top-level `import '../privateMethods'` runs before tests; Jest transforms that file with | ||
| // `enablePrivateMethods: false` for smoke namespace, so compilation throws | ||
| it('fails to compile: # private methods need enablePrivateMethods (only lightning/interop paths)', () => { | ||
| jest.resetModules(); | ||
| expect(() => { | ||
| require('../privateMethods'); | ||
| }).toThrow(/LWC1007:[\s\S]*Class private methods are not enabled/); | ||
| }); | ||
| }); |
This file contains hidden or 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
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.
modules/x/foo/bar.jsandmodules/x/foo/bar/baz.js.