Error: "Router must be defined in href" stenciljs router-v2 testing

Error: "Router must be defined in href" stenciljs router-v2 testing

我正在尝试测试模板组件。 我使用“stencil-router-v2”。 我的组件的渲染方法中有一个 link 和“href”函数: <a {...href(`/news/${this.page}`)} class="btn btn--primary btn--medium btn--view">View</a> 当我尝试测试它时,我看到下一个错误:“路由器必须在 href 中定义”。 你能给我解释一下如何正确测试“href”功能吗?我需要写什么测试代码才能通过测试?

我的组件代码:

import { Component, h, Prop, Event, EventEmitter } from '@stencil/core';
import { href } from 'stencil-router-v2';
import state from '../store/store';

@Component({
  tag: 'my-news-page',
  styleUrl: 'my-news-page.scss'
})

export class MyNewsPage {  
  @Prop() page: string;
  @Prop() news;

  @Event() newsDeleted: EventEmitter;

  deleteNewsHandler = id => {
    this.newsDeleted.emit(id);
  }

  componentWillRender() {
    this.news = state.newsList.find(news => news.id === +this.page);
  }

  render() {
    return (
      <section>
        <h3>{this.news.title}</h3>
        <p>{this.news.body}</p>
        <button class="btn btn--primary btn--medium btn--delete" onClick={() => this.deleteNewsHandler(this.news.id)}>Delete</button>
        <a {...href(`/news/${this.page}`)} class="btn btn--primary btn--medium btn--view">View</a>
      </section>
    )
  }
}

我的测试代码:

import { newSpecPage } from '@stencil/core/testing';
import { MyNewsPage } from '../my-news-page';
import state from '../../store/store';

state.newsList = [
  { id: 1, title: 'title1', body: 'content1' },
  { id: 2, title: 'title2', body: 'content2' },
  { id: 3, title: 'title3', body: 'content3' }
];

const ID = '1';

describe('my-news-page', () => {
  it('should display remaining items', () => {
    let page = new MyNewsPage();
    page.news = state.newsList;
    expect(page.news.length).toEqual(3);
  });

  it('renders', async () => {
    const page = await newSpecPage({
      components: [MyNewsPage],
      html: '<div></div>'
    });
    let cmp = page.doc.createElement('my-news-page');
    (cmp as any).page = ID;
    (cmp as any).news = state.newsList.find(news => news.id === +cmp.page);
    page.root.appendChild(cmp);
    await page.waitForChanges();
    expect(page.root).toMatchSnapshot();
  });
});

航站楼:

  my-news-page
    ✓ should display remaining items (7 ms)
    ✕ renders (37 ms)

  ● my-news-page › renders

    Router must be defined in href

      28 |         <p>{this.news.body}</p>
      29 |         <button class="btn btn--primary btn--medium btn--delete" onClick={() => this.deleteNewsHandler(this.news.id)}>Delete</button>
    > 30 |         {<a {...href(`/news/${this.page}`)} class="btn btn--primary btn--medium btn--view">View</a>}
         |                 ^
      31 |       </section>
      32 |     )
      33 |   }

      at Object.href (node_modules/stencil-router-v2/dist/index.js:106:15)
      at MyNewsPage.render (src/components/my-news-page/my-news-page.tsx:30:17)
      at callRender (node_modules/@stencil/core/internal/testing/index.js:421:46)
      at updateComponent (node_modules/@stencil/core/internal/testing/index.js:402:247)
      at node_modules/@stencil/core/internal/testing/index.js:397:22
      at then (node_modules/@stencil/core/internal/testing/index.js:459:47)
      at dispatchHooks (node_modules/@stencil/core/internal/testing/index.js:397:7)
      at a (node_modules/@stencil/core/internal/testing/index.js:387:18)
      at a (node_modules/@stencil/core/internal/testing/index.js:25:17)```

我认为您可以创建一个路由器,然后使用规范页面的 template 选项(您还必须将测试文件的扩展名更改为 .tsx 并导入 h):

import { Fragment, h, newSpecPage } from '@stencil/core/testing';
import { createRouter } from 'stencil-router-v2';

const Router = createRouter();

// ...

describe('my-news-page', () => {
  it('renders', async () => {
    const page = await newSpecPage({
      components: [MyNewsPage],
      template: () => (
        <Fragment>
          <Router>
            {/* You might have to define routes here, so probably
                best to import your app's router instead. */}
          </Router>

          <my-news-page
            page={ID}
            news={state.newsList.find(news +> news.id === ID)
          />
        </Fragment>
      ),
    });

    await page.waitForChanges();
    expect(page.root).toMatchSnapshot();
  });
});

使用 template 还可以简化道具设置等。请注意,这需要是一个 函数 返回 JSX。 Fragment 仅适用于较新的 Stencil 版本 afaik。

感谢 Thomas and Simon,我找到了解决方案。

我应该在此处将 const Router = createRouter(); 添加到我的代码中:

import { createRouter } from 'stencil-router-v2';
import { MyNewsPage } from '../my-news-page';
import state from '../../store/store';

state.newsList = [
  { id: 1, title: 'title1', body: 'content1' },
  { id: 2, title: 'title2', body: 'content2' },
  { id: 3, title: 'title3', body: 'content3' }
];

const ID = '1';

describe('my-news-page', () => {
  it('should display remaining items', () => {
    let page = new MyNewsPage();
    page.news = state.newsList;
    expect(page.news.length).toEqual(3);
  });

  it('renders', async () => {
    const page = await newSpecPage({
      components: [MyNewsPage],
      html: '<div></div>'
    });
    const Router = createRouter();
    let cmp = page.doc.createElement('my-news-page');
    (cmp as any).page = ID;
    (cmp as any).news = state.newsList.find(news => news.id === +cmp.page);
    page.root.appendChild(cmp);

    await page.waitForChanges();
    expect(page.root).toMatchSnapshot();
  });
});

现在我的测试工作正常。