Skip to content

Commit 5d43d3b

Browse files
authored
fix(rstest): rstest.importActual not work when imported from @rstest/core (#12908)
* fix(rstest): handle ESM imported rs/rstest variables in call_member_chain Previously, `rstest.importActual` and `rstest.requireActual` only worked when `rs` or `rstest` were free (global) variables. When imported from `@rstest/core` via ESM (e.g., `import { rstest } from '@rstest/core'`), the `for_name` parameter in `call_member_chain` would be the ESM specifier tag instead of the variable name, causing the check to fail. This fix extracts the variable name directly from the `call_expr.callee` AST node, enabling proper handling of ESM imported variables. * feat: only handle global `rs` and `rstest` variables when globals true * fix: clippy warnings * fix: remove globals option (other PR) * chore: useless Clippy lint ignore * test: split cases
1 parent 5ea17c9 commit 5d43d3b

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

crates/rspack_plugin_rstest/src/parser_plugin.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rspack_plugin_javascript::{
1515
use rspack_util::{SpanExt, atom::Atom, json_stringify, swc::get_swc_comments};
1616
use swc_core::{
1717
common::{Span, Spanned},
18-
ecma::ast::{CallExpr, Ident, MemberExpr, UnaryExpr},
18+
ecma::ast::{CallExpr, Callee, Ident, MemberExpr, UnaryExpr},
1919
};
2020

2121
static RSTEST_MOCK_FIRST_ARG_TAG: &str = "strip the import call from the first arg of mock series";
@@ -705,21 +705,31 @@ impl JavascriptParserPlugin for RstestParserPlugin {
705705
&self,
706706
parser: &mut JavascriptParser,
707707
call_expr: &CallExpr,
708-
for_name: &str,
708+
_for_name: &str,
709709
members: &[Atom],
710710
_members_optionals: &[bool],
711711
_member_ranges: &[Span],
712712
) -> Option<bool> {
713-
// Handle rs.requireActual and rs.importActual calls in any context
714-
if (for_name == "rs" || for_name == "rstest") && members.len() == 1 {
715-
match members[0].as_str() {
716-
"requireActual" => {
717-
return self.process_require_actual(parser, call_expr);
718-
}
719-
"importActual" => {
720-
return self.process_import_actual(parser, call_expr);
713+
// Handle rs.requireActual and rs.importActual calls
714+
// Extract the variable name from call_expr.callee to handle both:
715+
// 1. Global variables: rs.importActual() or rstest.importActual()
716+
// 2. ESM imports: import { rs } from '@rstest/core'; rs.importActual()
717+
if members.len() == 1
718+
&& let Callee::Expr(callee) = &call_expr.callee
719+
&& let Some(member_expr) = callee.as_member()
720+
&& let Some(ident) = member_expr.obj.as_ident()
721+
{
722+
let var_name = ident.sym.as_str();
723+
if var_name == "rs" || var_name == "rstest" {
724+
match members[0].as_str() {
725+
"requireActual" => {
726+
return self.process_require_actual(parser, call_expr);
727+
}
728+
"importActual" => {
729+
return self.process_import_actual(parser, call_expr);
730+
}
731+
_ => {}
721732
}
722-
_ => {}
723733
}
724734
}
725735
None
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { foo } from '../src/barrel'
2+
3+
rstest.mock('../src/foo')
4+
5+
const getGlobalActual = () => rstest.importActual('../src/foo');
6+
7+
it('importActual from global scope should works', async () => {
8+
expect(foo).toBe('mocked_foo')
9+
const originalFoo = await rstest.importActual('../src/foo')
10+
expect(originalFoo.value).toBe('foo')
11+
expect((await getGlobalActual()).value).toBe('foo')
12+
})
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { foo } from './src/barrel'
2+
import { rstest } from '@rstest/core';
23

34
rstest.mock('./src/foo')
45

56
const getActual = () => rstest.importActual('./src/foo');
67

78
it('importActual should works', async () => {
89
expect(foo).toBe('mocked_foo')
10+
expect((await getActual()).value).toBe('foo')
911
const originalFoo = await rstest.importActual('./src/foo')
1012
expect(originalFoo.value).toBe('foo')
11-
expect((await getActual()).value).toBe('foo')
1213
})

tests/rspack-test/configCases/rstest/mock/rspack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ module.exports = [
182182
}
183183
},
184184
rstestEntry("./mockFirstArgIsImport.js"),
185+
rstestEntry("./globals/importActual.js"),
185186
{
186187
...rstestEntry("./hoisted.js"),
187188
externals: {

0 commit comments

Comments
 (0)