diff --git a/.changeset/red-bikes-happen.md b/.changeset/red-bikes-happen.md new file mode 100644 index 000000000000..41da1e2b8b6a --- /dev/null +++ b/.changeset/red-bikes-happen.md @@ -0,0 +1,5 @@ +--- +'@astrojs/lit': patch +--- + +Added tests and fix a small edge case for when you call render with no props/attrs diff --git a/packages/integrations/lit/package.json b/packages/integrations/lit/package.json index eea99dd8d1b8..189ae1286f30 100644 --- a/packages/integrations/lit/package.json +++ b/packages/integrations/lit/package.json @@ -28,14 +28,16 @@ "scripts": { "build": "astro-scripts build \"src/**/*.ts\" && tsc", "build:ci": "astro-scripts build \"src/**/*.ts\"", - "dev": "astro-scripts dev \"src/**/*.ts\"" + "dev": "astro-scripts dev \"src/**/*.ts\"", + "test": "mocha" }, "dependencies": { "@lit-labs/ssr": "^2.1.0" }, "devDependencies": { "astro": "workspace:*", - "astro-scripts": "workspace:*" + "astro-scripts": "workspace:*", + "cheerio": "^1.0.0-rc.10" }, "peerDependencies": { "@webcomponents/template-shadowroot": "^0.1.0", diff --git a/packages/integrations/lit/server.js b/packages/integrations/lit/server.js index 1622ef6194dd..05f0d1f9d5a4 100644 --- a/packages/integrations/lit/server.js +++ b/packages/integrations/lit/server.js @@ -29,12 +29,14 @@ function* render(tagName, attrs, children) { // LitElementRenderer creates a new element instance, so copy over. const Ctr = getCustomElementConstructor(tagName); - for (let [name, value] of Object.entries(attrs)) { - // check if this is a reactive property - if (name in Ctr.prototype) { - instance.setProperty(name, value); - } else { - instance.setAttribute(name, value); + if (attrs) { + for (let [name, value] of Object.entries(attrs)) { + // check if this is a reactive property + if (name in Ctr.prototype) { + instance.setProperty(name, value); + } else { + instance.setAttribute(name, value); + } } } diff --git a/packages/integrations/lit/test/server.test.js b/packages/integrations/lit/test/server.test.js new file mode 100644 index 000000000000..a4b6912097da --- /dev/null +++ b/packages/integrations/lit/test/server.test.js @@ -0,0 +1,80 @@ +import { expect } from 'chai'; +import server from '../server.js' +import { LitElement, html } from 'lit' +import * as cheerio from 'cheerio' + +const { check, renderToStaticMarkup } = server + +describe('check', () => { + it('should be false with no component', async () => { + expect(await check()).to.equal(false) + }) + + it('should be false with a registered non-lit component', async () => { + const tagName = 'non-lit-component' + customElements.define(tagName, class TestComponent extends HTMLElement {}) + expect(await check(tagName)).to.equal(false) + }) + + it('should be true with a registered lit component', async () => { + const tagName = 'lit-component' + customElements.define(tagName, class extends LitElement {}) + expect(await check(tagName)).to.equal(true) + }) +}) + +describe('renderToStaticMarkup', () => { + it('should throw error if trying to render an unregistered component', async () => { + const tagName = 'non-registrered-component' + try { + await renderToStaticMarkup(tagName) + } catch (e) { + expect(e).to.be.an.instanceOf(TypeError) + } + }) + + it('should render emtpy component with default markup', async () => { + const tagName = 'nothing-component' + customElements.define(tagName, class extends LitElement {}) + const render = await renderToStaticMarkup(tagName) + expect(render).to.deep.equal({ + html: `<${tagName}>` + }) + }) + + it('should render component with default markup', async () => { + const tagName = 'simple-component' + customElements.define(tagName, class extends LitElement { + render() { + return html`

hola

` + } + }) + const render = await renderToStaticMarkup(tagName) + const $ = cheerio.load(render.html) + expect($(`${tagName} template`).html()).to.contain('

hola

') + }) + + it('should render component with properties and attributes', async () => { + const tagName = 'props-and-attrs-component' + const attr1 = 'test' + const prop1 = 'Daniel' + customElements.define(tagName, class extends LitElement { + static properties = { + prop1: { type: String }, + } + + constructor() { + super(); + this.prop1 = 'someone'; + } + + render() { + return html`

Hello ${this.prop1}

` + } + }) + const render = await renderToStaticMarkup(tagName, { prop1, attr1 }) + const $ = cheerio.load(render.html) + expect($(tagName).attr('attr1')).to.equal(attr1) + expect($(`${tagName} template`).text()).to.contain(`Hello ${prop1}`) + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b4facf0d316..5bce82a20342 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1349,11 +1349,13 @@ importers: '@lit-labs/ssr': ^2.1.0 astro: workspace:* astro-scripts: workspace:* + cheerio: ^1.0.0-rc.10 dependencies: '@lit-labs/ssr': 2.1.0 devDependencies: astro: link:../../astro astro-scripts: link:../../../scripts + cheerio: 1.0.0-rc.10 packages/integrations/netlify: specifiers: @@ -5485,7 +5487,7 @@ packages: dev: false /boolbase/1.0.0: - resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=} + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} /boxen/6.2.1: resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}