Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Continuous Integration (Docs)

on: [pull_request]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node: [22]

steps:
- uses: actions/checkout@v6
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- name: Installing project dependencies
run: |
npm ci
- name: Setup Playwright
run: |
npx playwright install --with-deps
- name: Build the website
run: |
npm run build
- name: Check Types
run: |
npm run check:types
- name: Test Docs
run: |
npm run test:docs
2 changes: 1 addition & 1 deletion .github/workflows/ci-win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
npm ci
- name: Test
run: |
npm test
npm run test
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ jobs:
- name: Lint
run: |
npm run lint
- name: Check Types
run: |
npm run check:types
- name: Test
run: |
npm test
npm run test
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ To develop for the project, you'll want to follow these steps:
1. Clone the repository
1. Have [NodeJS LTS](https://nodejs.org) installed and / or use `nvm` (see below)
1. Run `npm ci`
1. Run `npx playwright install`

### NVM

Expand Down Expand Up @@ -48,6 +49,11 @@ The website is built with [**Greenwood**](https://www.greenwoodjs.dev). To run t
- `npm run build` - Generate a production build
- `npm run serve` - Serve a production build

To run tests for the website, first make sure you have at least run `npm run build`, then:

- `npm run test:docs` - Run a single suite of tests with Vitest
- `npm run test:docs:tdd` - Run the test suite with Vitest in watch mode

### Sandbox

To assist in local development of WCC, there is a "sandbox" app built into the website, that can be used to validate a number of examples in the browser. (think of it as a storybook for WCC).
Expand Down
48 changes: 48 additions & 0 deletions docs/components/banner-cta/banner-cta.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './banner-cta.tsx';

describe('Components/Banner CTA', () => {
let bannerCta: HTMLElement;

describe('Default Behavior', () => {
const cta = 'npm i -D wc-compiler';

beforeEach(() => {
bannerCta = document.createElement('wcc-banner-cta');

document.body.appendChild(bannerCta);
});

it('should not be undefined', () => {
expect(bannerCta).not.equal(undefined);
});

it('should have the main overview text', () => {
const paragraph = bannerCta.querySelectorAll('p');

expect(paragraph.length).equal(1);
expect(paragraph[0].textContent.trim().replace(/\s+/g, ' ')).toContain(
'WCC (WC Compiler) is a NodeJS based package for server-rendering native Web Components.',
);
});

it('should have the copy to clipboard snippet', () => {
const pre = bannerCta.querySelectorAll('pre');

expect(pre.length).equal(1);
expect(pre[0].textContent.trim()).equal(`$ ${cta}`);
});

it('should have the copy to clipboard component', () => {
const ctcButton = bannerCta.querySelectorAll('wcc-ctc-button');

expect(ctcButton.length).equal(1);
expect(ctcButton[0].getAttribute('content')).equal(cta);
});
});

afterEach(() => {
bannerCta.remove();
bannerCta = undefined;
});
});
30 changes: 30 additions & 0 deletions docs/components/banner-splash/banner-splash.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './banner-splash.tsx';

describe('Components/Banner Splash', () => {
let bannerSplash: HTMLElement;

describe('Default Behavior', () => {
beforeEach(() => {
bannerSplash = document.createElement('wcc-banner-splash');

document.body.appendChild(bannerSplash);
});

it('should not be undefined', () => {
expect(bannerSplash).not.equal(undefined);
});

it('should have to the expected heading text', () => {
const heading = bannerSplash.querySelectorAll('h1');

expect(heading.length).equal(1);
expect(heading[0].textContent.trim().replace(/\s+/g, ' ')).equal('SSR for Web Components');
});
});

afterEach(() => {
bannerSplash.remove();
bannerSplash = undefined;
});
});
61 changes: 61 additions & 0 deletions docs/components/capability-box/capability-box.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './capability-box.tsx';

describe('Components/Capability Box', () => {
let capabilityBox: HTMLElement;

describe('Default Behavior', () => {
beforeEach(() => {
capabilityBox = document.createElement('wcc-capability-box');

document.body.appendChild(capabilityBox);
});

it('should not be undefined', () => {
expect(capabilityBox).not.equal(undefined);
});

it('should not have any heading text', () => {
const heading = capabilityBox.querySelectorAll('h4');

expect(heading.length).equal(1);
expect(heading[0].textContent).equal('');
});
});

describe('Custom Text and Heading', () => {
const customHeading = 'JSX';
const customContent = 'This is a custom feature box';

beforeEach(() => {
capabilityBox = document.createElement('wcc-capability-box');
capabilityBox.innerHTML = `<p>${customContent}</p>`;
capabilityBox.setAttribute('heading', customHeading);

document.body.appendChild(capabilityBox);
});

it('should not be undefined', () => {
expect(capabilityBox).not.equal(undefined);
});

it('should have the expected text from setting the heading attribute', () => {
const heading = capabilityBox.querySelectorAll('h4');

expect(heading.length).equal(1);
expect(heading[0].textContent).equal(customHeading);
});

it('should have the expected inner HTML text', () => {
const paragraph = capabilityBox.querySelectorAll('p');

expect(paragraph.length).equal(1);
expect(paragraph[0].textContent).equal(customContent);
});
});

afterEach(() => {
capabilityBox.remove();
capabilityBox = undefined;
});
});
4 changes: 2 additions & 2 deletions docs/components/capability-box/capability-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export default class CapabilityBox extends HTMLElement {
}

render() {
const heading = this.getAttribute('heading');
const heading = this.getAttribute('heading') ?? '';
const { innerHTML } = this;

return (
<div class={styles.container}>
<span class={styles.heading}>{heading}</span>
<h4 class={styles.heading}>{heading}</h4>
{innerHTML}
</div>
);
Expand Down
31 changes: 31 additions & 0 deletions docs/components/ctc-button/ctc-button.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './ctc-button.tsx';

describe('Components/Copy To Clipboard (Button)', () => {
const content = 'npm i -D wc-compiler';
let ctc: HTMLElement;

beforeEach(async () => {
ctc = document.createElement('wcc-ctc-button');

ctc.setAttribute('content', content);
document.body.appendChild(ctc);
});

describe('Default Behavior', () => {
it('should not be null', () => {
expect(ctc).not.equal(undefined);
});

it('should have an icon with the user provided content set', () => {
const icon = ctc.shadowRoot.querySelectorAll("[title='Copy to clipboard']");

expect(icon.length).to.equal(1);
});
});

afterEach(() => {
ctc.remove();
ctc = undefined;
});
});
73 changes: 73 additions & 0 deletions docs/components/feature-box/feature-box.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './feature-box.tsx';

describe('Components/Feature Box', () => {
let featureBox: HTMLElement;

describe('Default Behavior', () => {
beforeEach(() => {
featureBox = document.createElement('wcc-feature-box');

document.body.appendChild(featureBox);
});

it('should not be undefined', () => {
expect(featureBox).not.equal(undefined);
});

it('should not have any heading text', () => {
const heading = featureBox.querySelectorAll('h4');

expect(heading.length).equal(1);
expect(heading[0].textContent.trim()).equal('');
});

it('should not have an SVG mapped logo', () => {
const logo = featureBox.querySelectorAll('svg');

expect(logo.length).equal(0);
});
});

describe('Custom Text and Heading', () => {
const customHeading = 'JSX';
const customContent = 'This is a custom feature box';

beforeEach(() => {
featureBox = document.createElement('wcc-feature-box');
featureBox.innerHTML = `<p>${customContent}</p>`;
featureBox.setAttribute('heading', customHeading);

document.body.appendChild(featureBox);
});

it('should not be undefined', () => {
expect(featureBox).not.equal(undefined);
});

it('should have the expected text from setting the heading attribute', () => {
const heading = featureBox.querySelectorAll('h4');

expect(heading.length).equal(1);
expect(heading[0].textContent.trim()).equal(customHeading);
});

it('should have the expected inner HTML text', () => {
const paragraph = featureBox.querySelectorAll('p');

expect(paragraph.length).equal(1);
expect(paragraph[0].textContent).equal(customContent);
});

it('should not a mapped SVG logo', () => {
const logo = featureBox.querySelectorAll('svg');

expect(logo.length).equal(1);
});
});

afterEach(() => {
featureBox.remove();
featureBox = undefined;
});
});
8 changes: 4 additions & 4 deletions docs/components/feature-box/feature-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ export default class FeatureBox extends HTMLElement {
}

render() {
const heading = this.getAttribute('heading');
const heading = this.getAttribute('heading') ?? '';
const { innerHTML } = this;
const icon = FeatureBox.ICON_MAPPER[heading];
const icon = FeatureBox.ICON_MAPPER[heading] ?? '';

return (
<div class={styles.container}>
<span class={styles.heading}>
<h4 class={styles.heading}>
<span class={styles.icon}>{icon}</span>
<span>{heading}</span>
</span>
</h4>
{innerHTML}
</div>
);
Expand Down
43 changes: 43 additions & 0 deletions docs/components/footer/footer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './footer.tsx';

describe('Components/Footer', () => {
let footer: HTMLElement;

describe('Default Behavior', () => {
beforeEach(async () => {
footer = document.createElement('wcc-footer');

document.body.appendChild(footer);
});

it('should not be undefined', () => {
expect(footer).not.equal(undefined);
expect(footer.querySelectorAll('footer').length).equal(1);
});

it('should have a link for to the home page', () => {
const homeLink = footer.querySelectorAll('a[title="WCC Home Page"]');

expect(homeLink.length).equal(1);
expect(homeLink[0].getAttribute('href')).equal('/');
});

it('should have the WCC logo inside the home page link', () => {
const logo = footer.querySelectorAll('a[title="WCC Home Page"] > svg');

expect(logo.length).equal(1);
});

it('should have one instance of the social tray component', () => {
const socialTray = footer.querySelectorAll('wcc-social-tray');

expect(socialTray.length).equal(1);
});
});

afterEach(() => {
footer.remove();
footer = undefined;
});
});
Loading