Skip to content

Commit

Permalink
fix(testing): prevent find from throwing error when query has no ma…
Browse files Browse the repository at this point in the history
…tch (#5641)

* fix(testing): prevent `find` from throwing error when query has no match

This commit fixes an issue w/ our Puppeteer testing implementation where the `find()` method would throw an error if the query had no matching elements.

Fixes: #5639

STENCIL-1256

* it likes this better

* add non-shadow tests
  • Loading branch information
tanner-reits committed Apr 9, 2024
1 parent 30d3a3c commit b3886aa
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/testing/puppeteer/puppeteer-element.ts
Expand Up @@ -549,6 +549,11 @@ export async function find(page: pd.E2EPageInternal, rootHandle: puppeteer.Eleme

if (typeof selector === 'string' && selector.includes('>>>')) {
const handle = await page.$(selector);

if (!handle) {
return null;
}

const elm = new E2EElement(page, handle);
await elm.e2eSync();
return elm;
Expand Down
26 changes: 26 additions & 0 deletions test/end-to-end/src/components.d.ts
Expand Up @@ -36,6 +36,10 @@ export namespace Components {
}
interface ElementCmp {
}
interface EmptyCmp {
}
interface EmptyCmpShadow {
}
interface EnvData {
}
interface EventCmp {
Expand Down Expand Up @@ -187,6 +191,18 @@ declare global {
prototype: HTMLElementCmpElement;
new (): HTMLElementCmpElement;
};
interface HTMLEmptyCmpElement extends Components.EmptyCmp, HTMLStencilElement {
}
var HTMLEmptyCmpElement: {
prototype: HTMLEmptyCmpElement;
new (): HTMLEmptyCmpElement;
};
interface HTMLEmptyCmpShadowElement extends Components.EmptyCmpShadow, HTMLStencilElement {
}
var HTMLEmptyCmpShadowElement: {
prototype: HTMLEmptyCmpShadowElement;
new (): HTMLEmptyCmpShadowElement;
};
interface HTMLEnvDataElement extends Components.EnvData, HTMLStencilElement {
}
var HTMLEnvDataElement: {
Expand Down Expand Up @@ -284,6 +300,8 @@ declare global {
"dom-interaction": HTMLDomInteractionElement;
"dom-visible": HTMLDomVisibleElement;
"element-cmp": HTMLElementCmpElement;
"empty-cmp": HTMLEmptyCmpElement;
"empty-cmp-shadow": HTMLEmptyCmpShadowElement;
"env-data": HTMLEnvDataElement;
"event-cmp": HTMLEventCmpElement;
"import-assets": HTMLImportAssetsElement;
Expand Down Expand Up @@ -328,6 +346,10 @@ declare namespace LocalJSX {
}
interface ElementCmp {
}
interface EmptyCmp {
}
interface EmptyCmpShadow {
}
interface EnvData {
}
interface EventCmp {
Expand Down Expand Up @@ -376,6 +398,8 @@ declare namespace LocalJSX {
"dom-interaction": DomInteraction;
"dom-visible": DomVisible;
"element-cmp": ElementCmp;
"empty-cmp": EmptyCmp;
"empty-cmp-shadow": EmptyCmpShadow;
"env-data": EnvData;
"event-cmp": EventCmp;
"import-assets": ImportAssets;
Expand Down Expand Up @@ -408,6 +432,8 @@ declare module "@stencil/core" {
"dom-interaction": LocalJSX.DomInteraction & JSXBase.HTMLAttributes<HTMLDomInteractionElement>;
"dom-visible": LocalJSX.DomVisible & JSXBase.HTMLAttributes<HTMLDomVisibleElement>;
"element-cmp": LocalJSX.ElementCmp & JSXBase.HTMLAttributes<HTMLElementCmpElement>;
"empty-cmp": LocalJSX.EmptyCmp & JSXBase.HTMLAttributes<HTMLEmptyCmpElement>;
"empty-cmp-shadow": LocalJSX.EmptyCmpShadow & JSXBase.HTMLAttributes<HTMLEmptyCmpShadowElement>;
"env-data": LocalJSX.EnvData & JSXBase.HTMLAttributes<HTMLEnvDataElement>;
"event-cmp": LocalJSX.EventCmp & JSXBase.HTMLAttributes<HTMLEventCmpElement>;
"import-assets": LocalJSX.ImportAssets & JSXBase.HTMLAttributes<HTMLImportAssetsElement>;
Expand Down
11 changes: 11 additions & 0 deletions test/end-to-end/src/non-existent-element/empty-cmp-shadow.tsx
@@ -0,0 +1,11 @@
import { Component, h, Host } from '@stencil/core';

@Component({
tag: 'empty-cmp-shadow',
shadow: true,
})
export class EmptyComponentShadow {
render() {
return <Host>I have no children!</Host>;
}
}
12 changes: 12 additions & 0 deletions test/end-to-end/src/non-existent-element/empty-cmp.tsx
@@ -0,0 +1,12 @@
import { Component, h, Host } from '@stencil/core';

@Component({
tag: 'empty-cmp',
shadow: false,
scoped: false,
})
export class EmptyComponent {
render() {
return <Host>I have no children!</Host>;
}
}
@@ -0,0 +1,55 @@
import { newE2EPage } from '@stencil/core/testing';

describe('Querying non-existent element(s)', () => {
describe('Shadow DOM', () => {
it('returns `null` if the element does not exist', async () => {
// create a new puppeteer page
const page = await newE2EPage({
html: `
<empty-cmp-shadow></empty-cmp-shadow>
`,
});

const elm = await page.find('empty-cmp-shadow >>> .non-existent');
expect(elm).toBeNull();
});

it('returns an empty array if no elements match the selector', async () => {
// create a new puppeteer page
const page = await newE2EPage({
html: `
<empty-cmp-shadow></empty-cmp-shadow>
`,
});

const elm = await page.findAll('empty-cmp-shadow >>> .non-existent');
expect(elm).toEqual([]);
});
});

describe('Light DOM', () => {
it('returns `null` if the element does not exist', async () => {
// create a new puppeteer page
const page = await newE2EPage({
html: `
<empty-cmp></empty-cmp>
`,
});

const elm = await page.find('empty-cmp >>> .non-existent');
expect(elm).toBeNull();
});

it('returns an empty array if no elements match the selector', async () => {
// create a new puppeteer page
const page = await newE2EPage({
html: `
<empty-cmp></empty-cmp>
`,
});

const elm = await page.findAll('empty-cmp >>> .non-existent');
expect(elm).toEqual([]);
});
});
});
10 changes: 10 additions & 0 deletions test/end-to-end/src/non-existent-element/readme.md
@@ -0,0 +1,10 @@
# empty-cmp



<!-- Auto Generated Below -->


----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*

0 comments on commit b3886aa

Please sign in to comment.