UNPKG

@lwc/jest-transformer

Version:

Jest transformer for LWC and engine

105 lines (95 loc) 4 kB
/* * 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 */ const { getImportInfo, resolvedPromiseTemplate } = require('./utils'); const APEX_IMPORT_IDENTIFIER = '@salesforce/apex'; /** * Instead of using @babel/template, we manually build the variable declaration * and try/catch block since we don't know how many named imports we have and * each one needs it's own try/catch block. */ function insertNamedImportReplacement(t, path, resource) { // jest.fn(); const jestFn = t.callExpression( t.memberExpression(t.identifier('jest'), t.identifier('fn')), [] ); // function() { return Promise.resolve(); }; const resolvedPromise = t.functionExpression( null, [], t.blockStatement([ t.returnStatement( t.callExpression( t.memberExpression(t.identifier('Promise'), t.identifier('resolve')), [] ) ), ]) ); // we know refreshApex returns a Promise, default to jest.fn() to try to be future proof const fallbackValue = resource === 'refreshApex' ? resolvedPromise : jestFn; // `let refreshApex;` path.insertBefore(t.variableDeclaration('let', [t.VariableDeclarator(t.identifier(resource))])); // try/catch block path.insertBefore( t.tryStatement( // `refreshApex = require('@salesforce/apex').refreshApex;` t.blockStatement([ t.expressionStatement( t.assignmentExpression( '=', t.identifier(resource), t.memberExpression( t.callExpression(t.identifier('require'), [ t.stringLiteral(APEX_IMPORT_IDENTIFIER), ]), t.identifier(resource) ) ) ), ]), // catch block: `refreshApex = jest.fn()` t.catchClause( t.identifier('e'), t.blockStatement([ t.expressionStatement( t.assignmentExpression('=', t.identifier(resource), fallbackValue) ), ]) ) ) ); } module.exports = function ({ types: t }) { return { visitor: { ImportDeclaration(path) { const { importSource, resourceNames } = getImportInfo(path, true); // if '@salesforce/apex' is the exact source that means we have named imports // e.g. `import { refreshApex, getSObjectValue } from '@salesforce/apex';` if (importSource === APEX_IMPORT_IDENTIFIER) { // add a try/catch block defining the imported resource for each named import resourceNames.forEach((resource) => { insertNamedImportReplacement(t, path, resource); }); // remove the original import statement path.remove(); } else if (importSource.startsWith(APEX_IMPORT_IDENTIFIER)) { // importing anything after '@salesforce/apex' means they're getting a single Apex method as the default import // e.g. `import myMethod from '@salesforce/apex/FooController.fooMethod';` path.replaceWithMultiple( resolvedPromiseTemplate({ RESOURCE_NAME: t.identifier(resourceNames[0]), IMPORT_SOURCE: t.stringLiteral(importSource), MOCK_NAME: `__lwcJestMock_${resourceNames[0]}`, }) ); } }, }, }; };