You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Stenciljs测试中用newE2EPage/newSpecPage触发生命周期方法

在Stencil.js的Spec/E2E测试中触发connectedCallback/disconnectedCallback且避免重复调用componentWillLoad

先准备测试用的组件示例

首先我们需要一个带生命周期计数的组件,方便验证测试逻辑:

import { Component, h } from '@stencil/core';

@Component({
  tag: 'my-cmp',
})
export class MyCmp {
  willLoadCount = 0;
  connectedCount = 0;
  disconnectedCount = 0;

  componentWillLoad() {
    this.willLoadCount++;
  }

  connectedCallback() {
    this.connectedCount++;
  }

  disconnectedCallback() {
    this.disconnectedCount++;
  }

  render() {
    return <div>Test Component</div>;
  }
}

一、使用newSpecPage进行单元测试(Spec测试)

Spec测试运行在JSDOM环境,逻辑和官方原生DOM操作类似,只需通过newSpecPage获取页面上下文:

import { newSpecPage } from '@stencil/core/testing';
import { MyCmp } from './my-cmp';

describe('my-cmp lifecycle tests', () => {
  it('should trigger connected/disconnected without re-running componentWillLoad', async () => {
    // 1. 创建Spec页面并挂载组件
    const page = await newSpecPage({
      components: [MyCmp],
      html: '<my-cmp></my-cmp>',
    });

    // 获取组件实例
    const cmp = page.body.querySelector('my-cmp') as MyCmp;
    
    // 验证第一次挂载的计数
    expect(cmp.willLoadCount).toBe(1);
    expect(cmp.connectedCount).toBe(1);
    expect(cmp.disconnectedCount).toBe(0);

    // 2. 移除组件,触发disconnectedCallback
    cmp.remove();
    await page.waitForChanges(); // 等待Stencil更新状态
    expect(cmp.disconnectedCount).toBe(1);

    // 3. 重新添加组件到页面,触发connectedCallback但不会触发componentWillLoad
    page.body.appendChild(cmp);
    await page.waitForChanges();
    
    // 验证最终计数:willLoad只执行一次,connected执行两次,disconnected执行一次
    expect(cmp.willLoadCount).toBe(1);
    expect(cmp.connectedCount).toBe(2);
    expect(cmp.disconnectedCount).toBe(1);
  });
});

二、使用newE2EPage进行端到端测试(E2E测试)

E2E测试运行在真实浏览器环境(基于Playwright),所有DOM操作和属性访问需要通过page.evaluate()在页面上下文内执行:

import { newE2EPage } from '@stencil/core/testing';

describe('my-cmp e2e lifecycle tests', () => {
  it('should trigger connected/disconnected without re-running componentWillLoad', async () => {
    const page = await newE2EPage();

    // 1. 首次挂载组件
    await page.setContent('<my-cmp></my-cmp>');
    await page.waitForChanges();

    // 获取初始计数
    const initialCounts = await page.evaluate(() => {
      const cmp = document.querySelector('my-cmp');
      return {
        willLoad: cmp.willLoadCount,
        connected: cmp.connectedCount,
        disconnected: cmp.disconnectedCount,
      };
    });
    expect(initialCounts.willLoad).toBe(1);
    expect(initialCounts.connected).toBe(1);
    expect(initialCounts.disconnected).toBe(0);

    // 2. 移除组件,触发disconnectedCallback
    await page.evaluate(() => {
      const cmp = document.querySelector('my-cmp');
      cmp.remove();
    });
    await page.waitForChanges();

    const afterRemoveCounts = await page.evaluate(() => {
      const cmp = document.querySelector('my-cmp'); // 移除后实例仍存在
      return { disconnected: cmp.disconnectedCount };
    });
    expect(afterRemoveCounts.disconnected).toBe(1);

    // 3. 重新添加组件到页面
    await page.evaluate(() => {
      const cmp = document.querySelector('my-cmp');
      document.body.appendChild(cmp);
    });
    await page.waitForChanges();

    // 验证最终计数
    const finalCounts = await page.evaluate(() => {
      const cmp = document.querySelector('my-cmp');
      return {
        willLoad: cmp.willLoadCount,
        connected: cmp.connectedCount,
        disconnected: cmp.disconnectedCount,
      };
    });
    expect(finalCounts.willLoad).toBe(1); // componentWillLoad仅执行一次
    expect(finalCounts.connected).toBe(2); // connected执行两次
    expect(finalCounts.disconnected).toBe(1); // disconnected执行一次
  });
});

关键注意点

  • Spec测试中,await page.waitForChanges()必须调用,确保Stencil完成组件状态更新。
  • E2E测试中,测试代码无法直接访问浏览器上下文变量,所有DOM操作和属性读取都要通过page.evaluate()执行。
  • 组件实例在移除后不会被销毁,重新添加时仅触发connectedCallback,不会再次执行componentWillLoad(该方法仅在组件首次挂载前执行一次)。

内容的提问来源于stack exchange,提问作者Safa Alai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:03:22