Table Excerpt Include | ||||||||
---|---|---|---|---|---|---|---|---|
|
Table Excerpt Include | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Tabla de contenidos | ||||||
---|---|---|---|---|---|---|
|
Advertencia |
---|
Las guías de desarrollo son un documento que busca facilitar el onboarding y la homogeneidad de los proyectos en la STIC. La STIC podrá estudiar los casos excepcionales los cuales serán gestionados a través de los responsables del proyecto correspondiente y autorizados por el Área de Gobernanza de la STIC. Asimismo cualquier aspecto no recogido en estas guías deberá regirse en primera instancia por las guías técnicas correspondientes al esquema nacional de seguridad y esquema nacional de interoperabilidad según correspondencia y en su defecto a los marcos normativos y de desarrollo software establecidos por la Junta de Andalucía, debiendo ser puesto de manifiesto ante la STIC. La STIC se reserva el derecho a la modificación de la guía sin previo aviso, tras lo cual, notificará del cambio a los actores implicados para su adopción inmediata según la planificación de cada proyecto. En el caso de que algún actor considere conveniente y/o necesario el incumplimiento de alguna de las normas y/o recomendaciones, deberá aportar previamente la correspondiente justificación fehaciente documentada de la solución alternativa propuesta, así como toda aquella documentación que le sea requerida por la STIC para proceder a su validación técnica. Contacto Arquitectura: l-arquitectura.stic@juntadeandalucia.es |
Los cambios en la normativa documentados, vendrán acompañados de un registro de las modificaciones. De este modo se podrá realizar un seguimiento y consultar su evolución. Ordenándose de mas recientes a menos recientes, prestando especial cuidado a las cabeceras de la tablas dónde se indican las fechas de entrada en vigor y versión.
Expandir | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||
|
En este documento se describirán las los principales pautas aspectos a tener en cuenta a la hora de diseñar y ejecutar test en los desarrollos frontales. Importante e, que serán ejecutables dentro de los procesos de IC de la STIC.
El código de los ejemplos compartidos en esta guía de diseño se puede encontrar en el espacio público
Este apartado pretende compartir algunas configuraciones consideradas de utilidad para una correcta ejecución de los test.
@open-wc/testing
@types/mocha
@web/test-runner
@web/test-runner-puppeteerplaywright
sinon
puppeteerplaywright
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
mport// { Este archivo es la configuración de Web Test Runner. Aquí puedes configurar los plugins, los navegadores, los reporters, etc. import { esbuildPlugin } from '@web/dev-server-esbuild'; import { puppeteerLauncherplaywrightLauncher } from '@web/test-runner-puppeteerplaywright'; import { defaultReporter } from '@web/test-runner'; export defaultfunction playwrightLauncherExtended(options, browserName) { plugins:const [ launcher = playwrightLauncher(options); esbuildPlugin({ ts: true, tsconfig: launcher.name = browserName??launcher.name; return launcher; } export default { plugins: [ esbuildPlugin({ ts: true, tsconfig: 'tsconfig.dev.json', // Asegúrate de que esbuild use tu tsconfig.json loaders: { '.ts': 'ts', } }), ], browsers: [puppeteerLauncher playwrightLauncherExtended({ launchOptions: { argsproduct: ['--no-sandboxchromium', '--disable-setuid-sandbox'] } })], reporters:[ launchOptions: { defaultReporter({ reportTestResults channel: true, reportTestProgress: true })], nodeResolve: true, preserveSymlinks: true, rootDir: '.'chrome', }, }, 'Chrome'), // Lanza Chromium playwrightLauncherExtended({ product: 'chromium', files: ['packages/**/*.test.ts'], mimeTypes launchOptions: { '**/*.ts' channel: 'jsmsedge', }, }; }, 'Microsoft Edge'), playwrightLauncherExtended({ product: 'firefox', }, 'Mozilla Firefox') // Lanza Firefox ], reporters: [defaultReporter({ reportTestResults: true, reportTestProgress: true })], nodeResolve: true, preserveSymlinks: true, rootDir: '.', files: ['test/**/*.test.ts'], mimeTypes: { '**/*.ts': 'js', } }; |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
{
....
"scripts": {
"test": "wtr --coverage",
"test:debug": "wtr --debug --watch",
"build:dev":"tsc --project tsconfig.dev.json",
"build":"npm i -ddd && tsc",
"postinstall": "npx playwright install --with-deps"
},
"devDependencies": {
....
"@open-wc/testing": "4.0.0",
"@types/mocha": "10.0.9",
"@web/dev-server-esbuild": "1.0.2",
"@web/test-runner": "0.19.0",
"@web/test-runner-playwright": "0.11.0",
"lit": "2.7.4",
"playwright": "1.48.1",
"sinon": "19.0.2",
"typescript": "5.6.3"
....
},
...
} |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
{
"compilerOptions": {
"target": "es2018",
"module": "esnext",
"moduleResolution": "node",
"noEmitOnError": true,
"lib": ["es2017", "dom"],
"strict": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"importHelpers": true,
"outDir": "dist",
"sourceMap": true,
"inlineSources": true,
"rootDir": ".",
"declaration": true,
"declarationMap": true
},
"include": ["./src/**/*.ts"],
"exclude": [
"./dist","./node_modules"
]
} |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declarationDir": "./types/"
}
} |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
import { html, LitElement } from "lit";
import { property } from "lit/decorators.js";
export class Example extends LitElement{
@property({ type: String, attribute: 'some-attribute'})
public someProperty: string = "default value";
constructor() {
super();
}
connectedCallback() {
super.connectedCallback();
console.debug(`Cargado componente ${this.tagName} `);
}
render(): any {
return html`<h2>componente creado</h2>
<p id="property-value">${this.someProperty}</p>`;
}
}
customElements.define('example-test-component', Example); |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element
import { defineCE, expect, fixture, fixtureCleanup, html, unsafeStatic} from "@open-wc/testing";
//Importamos el componente
import { Example } from "../index";
describe("Testing Lit WebComponent ", () => {
//Se restaura el sandbox y se limpia el fixture después de cada test
afterEach(() => {
fixtureCleanup();
});
//test de renderizado del componente example-test-component
it("should render a web component", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
});
it("should render a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
});
}); |
Advertencia | ||
---|---|---|
| ||
//Cuidado!!!!! este código genera acoplamiento al html generado por el render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element
import { defineCE, elementUpdated, expect, fixture, fixtureCleanup, html, unsafeStatic} from "@open-wc/testing";
//Importamos el componente
import { Example } from "../index";
describe("Testing Lit WebComponent ", () => {
//creación de un sandbox para el mock
before(() => {
});
//Se restaura el sandbox y se limpia el fixture después de cada test
afterEach(() => {
fixtureCleanup();
});
//test de renderizado del componente example-test-component
it("should render a default value of property", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('default value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('default value');
});
it("should render a default value of property in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('default value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('default value');
});
it("should render a initialize value property", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component .someProperty=${'init value'} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
});
it("should render a initialize value property in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} .someProperty=${'init value'}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
});
it("should render a changed value property", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component .someProperty=${'init value'} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
el.someProperty = 'new value';
await elementUpdated(el);
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a changed value property in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} .someProperty=${'init value'}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
el.someProperty = 'new value';
await elementUpdated(el);
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a reactive changed value property", async () => {
let propertyReactiveBind = 'init value';
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component .someProperty=${propertyReactiveBind} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
propertyReactiveBind = 'new value';
//Tenemos que hacer esto ya que no existe un método para actualizar la propiedad de forma reactiva a través del html desde un entorno de test.
el.someProperty = propertyReactiveBind;
await elementUpdated(el);
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a reactive changed value property in a web component with random test tag", async () => {
let propertyReactiveBind = 'init value';
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} .someProperty=${propertyReactiveBind}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
propertyReactiveBind = 'new value';
//Tenemos que hacer esto ya que no existe un método para actualizar la propiedad de forma reactiva a través del html desde un entorno de test.
el.someProperty = propertyReactiveBind;
await elementUpdated(el);
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
}); |
Advertencia | ||
---|---|---|
| ||
//Cuidado!!!!! este código genera acoplamiento al html generado por el render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor del atributo se renderiza correctamente, no solo que se ha definido |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element
import { defineCE, elementUpdated, expect, fixture, fixtureCleanup, html, unsafeStatic} from "@open-wc/testing";
//Importamos el componente
import { Example } from "../index";
describe("Testing Lit WebComponent ", () => {
//creación de un sandbox para el mock
before(() => {
});
//Se restaura el sandbox y se limpia el fixture después de cada test
afterEach(() => {
fixtureCleanup();
});
//test de renderizado del componente example-test-component
it("should render a default value of attribute", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.not.exist;
expect(el.someProperty).to.equal('default value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('default value');
});
it("should render a default value of attribute in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.not.exist;
expect(el.someProperty).to.equal('default value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('default value');
});
it("should render a initialize value attribute", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component some-attribute=${'init value'} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
});
it("should render a initialize value attribute in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} some-attribute=${'init value'}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
});
it("should render a changed value attribute", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component some-attribute=${'init value'} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
el.setAttribute('some-attribute', 'new value');
await elementUpdated(el);
expect(el.getAttribute('some-attribute')).to.equal('new value');
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a changed value attribute in a web component with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} some-attribute=${'init value'}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
el.setAttribute('some-attribute', 'new value');
await elementUpdated(el);
expect(el.getAttribute('some-attribute')).to.equal('new value');
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a reactive changed value attribute", async () => {
let propertyReactiveBind = 'init value';
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component some-attribute=${propertyReactiveBind} ></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
propertyReactiveBind = 'new value';
//Tenemos que hacer esto ya que no existe un método para actualizar la propiedad de forma reactiva a través del html desde un entorno de test.
el.setAttribute('some-attribute', propertyReactiveBind);
await elementUpdated(el);
expect(el.getAttribute('some-attribute')).to.equal('new value');
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
it("should render a reactive changed value attribute in a web component with random test tag", async () => {
let propertyReactiveBind = 'init value';
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag} some-attribute=${propertyReactiveBind}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
expect(el.getAttribute('some-attribute')).to.equal('init value');
expect(el.someProperty).to.equal('init value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('init value');
propertyReactiveBind = 'new value';
//Tenemos que hacer esto ya que no existe un método para actualizar la propiedad de forma reactiva a través del html desde un entorno de test.
el.setAttribute('some-attribute', propertyReactiveBind);
await elementUpdated(el);
expect(el.getAttribute('some-attribute')).to.equal('new value');
expect(el.someProperty).to.equal('new value');
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(el.shadowRoot?.getElementById("property-value")?.textContent).to.equal('new value');
});
}); |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element
import { defineCE, expect, fixture, fixtureCleanup, html, oneEvent, unsafeStatic} from "@open-wc/testing";
//Importamos el componente
import { Example } from "../src/index";
describe("Testing Lit WebComponent ", () => {
//Se restaura el sandbox y se limpia el fixture después de cada test
afterEach(() => {
fixtureCleanup();
});
//test de renderizado del componente example-test-component
it("should receive a web component custom event", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<example-test-component></example-test-component>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
setTimeout(() => el.fireEvent());
const { detail } = await oneEvent(el, 'example-event');
expect(detail).to.deep.equal ({ message: "Hello world" });
});
it("should receive a web component custom event with random test tag", async () => {
const tag = defineCE(class extends Example{});
const unsafeTag = unsafeStatic(tag);
//await fixture espera hasta que se renderice el componente
const el = await fixture< Example >(html`<${unsafeTag}></${unsafeTag}>`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
setTimeout(() => el.fireEvent());
const { detail } = await oneEvent(el, 'example-event');
expect(detail).to.deep.equal({ message: "Hello world" });
});
}); |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element
import { defineCE, expect, fixture, fixtureCleanup, html, unsafeStatic } from "@open-wc/testing";
import { LitElement } from "lit";
//Creación de un componente LitElement dinámico
const customElementWithProperties = defineCE(
class extends LitElement{
static properties = {
someProperty: { type: String },
};
constructor() {
super();
}
connectedCallback() {
super.connectedCallback();
console.debug(`Cargado componente ${this.tagName} `);
}
render(): any {
return html`<h2>componente creado STAND-ALONE</h2>`;
}
}
);
//Obtención del tag del componente para su renderizado dinámico
const customElementWithPropertiesTag = unsafeStatic(customElementWithProperties);
//Definición de la suit
describe("Testing Lit WebComponent ", () => {
//Se restaura el sandbox y se limpia el fixture después de cada test
afterEach(() => {
fixtureCleanup();
});
//test de renderizado del componente customizado
it("should render a web component", async () => {
//await fixture espera hasta que se renderice el componente
const el = await fixture< LitElement >(html`<${customElementWithPropertiesTag}></${customElementWithPropertiesTag}`);
expect(el).to.exist;
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(el.shadowRoot).to.exist;
});
}); |
La herramienta de ejecución de los test es el Web Test Runner (wtr).
La configuración ofrecida, permite la transpilación de forma directa por el wtr. Dicha transpilación se genera en memoria que, salvo algunos casos concretos (por ejemplo dentro de un iframe), no tiene implicación.
Nota | ||
---|---|---|
| ||
EL script utilizado es test → npm run test |
Para la depurar WTR ofrece la posiblidad de probarlo en el navegador de forma manual (opción D) y ahí poder hacer la depuración que se considere necesaria. Combinado con la opción --watch, se realizará una reejecución con cada cambio detectado.
Otra facilidad que ofrece WTR es que, de todos los test lanzados, puedes centrarte en uno solo (opción F). La lista de ficheros con test fallidos en su ejecución aparecerán en rojo.
Nota | ||
---|---|---|
| ||
EL script utilizado es test → npm run test:debug |
Se puede configurar para lanzar los test en diferentes navegadores. Por normativa, los desarrollos deben ser compatibles con los navegadores evergreen ( Chrome/Chromium, Microsoft Edge, Firefox). Safari no es obligatorio actualmente
Bloque de código | ||||||
---|---|---|---|---|---|---|
| ||||||
npx playwright install --with-deps |
Para ver diferentes opciones que ofrece el instalador podéis usar la opción de help
Bloque de código | ||||||
---|---|---|---|---|---|---|
| ||||||
npx playwright install --help |
Con la configuración establecida se ejecutarán los test para todos los navegadores configurados.
Advertencia | ||
---|---|---|
| ||
No está permitido el uso de playwright como parte del desarrollo y definición de los test. Solo está permitido su uso como launcher. |
Advertencia | ||
---|---|---|
| ||
Un iframe genera un contexto independiente para la ejecución del código alojado dentro de él. Esto implica que se debe incluir las dependencias necesarias para la ejecución de forma manual. |
Advertencia | ||
---|---|---|
| ||
Web Test Runner (WTR) genera la transpilación de los elemento en memoria. Esto implica que los ficheros js resultantes no están disponibles para importarlos dentro del iframe. Para poder acceder a ellos se debe:
|
Advertencia | ||
---|---|---|
| ||
El código compartido para el ejemplo solo es válido para el ámbito del testing por motivos de seguridad. En ningún caso se creará un componente que haga uso de un iframe y rellene el contenido del iframe de esta forma. Se deberá utilizar la manera tradicional (src) combinado con los CSP |
Advertencia | ||
---|---|---|
| ||
A veces la carga de iframe se ralentiza y supera los 2s de timeout, se recomiendo aumentar el timeout, como se muestra en el ejemplo |
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
import { fixture, expect, html, elementUpdated} from "@open-wc/testing";
import { Example } from "../src/index";
import { LitElement } from "lit";
describe("Test Lit component inside iframe", () => {
it("should render the Lit component inside an iframe and access shadow DOM", async function() {
this.timeout(10000);
// Cargar un iframe con el componente
const el = await fixture<HTMLIFrameElement>(html` <iframe srcdoc="${getIframeHtmlCodeForExistingComponent("example-test-component")}" width="600" height="400"></iframe> `);
// Esperar a que el iframe se cargue completamente
await new Promise((resolve) => {
el.onload = () => resolve(true);
});
// Acceder al documento del iframe
const iframeDocument = el.contentDocument!;
const exampleComponent = iframeDocument.querySelector<Example>("example-test-component");
// Verificar que el componente Lit se ha renderizado dentro del iframe
expect(exampleComponent).to.exist;
// Esperar a que se complete la actualización del componente Lit dentro del iframe
await elementUpdated(exampleComponent!);
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(exampleComponent?.shadowRoot).to.exist;
// Verificar el contenido renderizado del shadow DOM
expect(exampleComponent?.someProperty).to.equal("default value");
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(exampleComponent?.shadowRoot?.getElementById("property-value")?.textContent).to.equal("default value");
});
it("should render the Lit component with random tag inside an iframe and access shadow DOM", async function() {
this.timeout(10000);
const tag = 'example-test-component-' + Math.random().toString(36).substring(7);
// Cargar un iframe con el componente
const el = await fixture<HTMLIFrameElement>(html` <iframe srcdoc="${getIframeHtmlCodeForCustomComponent(tag)}" width="600" height="400"></iframe> `);
// Esperar a que el iframe se cargue completamente
await new Promise((resolve) => {
el.onload = () => resolve(true);
});
// Acceder al documento del iframe
const iframeDocument = el.contentDocument!;
const exampleComponent = iframeDocument.querySelector<LitElement>(tag);
// Verificar que el componente Lit se ha renderizado dentro del iframe
expect(exampleComponent).to.exist;
// Esperar a que se complete la actualización del componente Lit dentro del iframe
await elementUpdated(exampleComponent!);
// si tiene shadowRoot es que es un webcomponent y que se ha renderizado de forma correcta
expect(exampleComponent?.shadowRoot).to.exist;
//Cuidado!!!!! este código genera acoplamiento al render del componente, no es recomendable ya que los test deben ser funcionales. Nos sirve para testear que el valor de la propiedad se renderiza correctamente, no solo que se ha definido
expect(exampleComponent?.shadowRoot?.getElementById("html-iframe-rendered")?.textContent).to.equal("testing");
});
});
const getIframeHtmlCodeForExistingComponent = (componentName: string) => {
return `<html>
<head>
<!-- Incluir los módulos de Lit desde el propio servidor de testing-->
<script type='module' src='${window.location.origin}/node_modules/lit/index.js'></script>
<!-- Importar el componente -->
<script type='module'>
import '/dist/src/index.js';
</script>
</head>
<body><${componentName}></${componentName}></body></html>`;
};
const getIframeHtmlCodeForCustomComponent = (componentName: string) => {
return `<html>
<head>
<script type='module'>
//Incluir los módulos de Lit desde el propio servidor de testing
import { LitElement, html } from "${window.location.origin}/node_modules/lit/index.js";
//Definir el componente
customElements.define(
'${componentName}',
class extends LitElement {
static get properties() {
return {
somePropertyInsideIframe: { type: String }
};
}
constructor() {
super();
}
connectedCallback() {
|
Bloque de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
//Importante que los import vengas de @open-wc/testing para que tener la máxima compatibilidad con lit-element import { defineCE, elementUpdated, expect, fixture, fixtureCleanup, html, unsafeStatic, waitUntil } from "@open-wc/testing"; //Librería de MOCK import sinon, { SinonSpy } from "sinon"; //Creación de un componente LitElement dinámico const customElementWithProperties = defineCE( class extends LitElement{ static properties = { someProperty: { type: String }, }; constructor() { super(); } connectedCallback() { super.connectedCallback(); console.debuglog(`Cargado"Cargado componente ${this.tagName} `componentName} dentro del iframe"); } render(): any { return html`<h2>componente creado STAND-ALONE</h2>`; } } } ); //Obtención del tag del componente para su renderizado dinámico const customElementWithPropertiesTag = unsafeStatic(customElementWithProperties); //DefiniciónImportante los decaracteres la suit describe("Testing Lit WebComponent ", () => { let sandbox: sinon.SinonSandbox; //creación de un sandbox para el mock before(() => { sandbox = sinon.createSandbox(); }); //Se restaura el sandbox y se limpia el fixture después de cada test afterEach(() => { sandbox.restore(); fixtureCleanup(); }); //test de renderizado de un componente LitElement it("should render a web component", async () => { const el = await fixture< LitElement >(html`<${customElementWithPropertiesTag}></${customElementWithPropertiesTag}`); expect(el).to.exist; expect(el.shadowRoot).to.exist; }); }); |
especiales se deben escapar con \ para que no se interpreten como caracteres especiales
render() {
return html\`<p id='html-iframe-rendered'>testing</p>\`;
}
}
);
</script>
</head>
<body><${componentName}></${componentName}></body></html>`;
}; |
Table Excerpt Include | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Table Excerpt Include | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Table Excerpt Include | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|