Simpleview CMS Component Library
npm install @simpleview/cms-component-librarypackage.json
shell
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
`
2. Clone this repository to your local machine
- Example using TortoiseGit:
1. Navigate (or created as needed) to D:\cms30\ via File Explorer (this is the recommend folder location, but not required).
2. Right click inside the folder and select "Git Clone..."
3. Use git@github.com:simpleviewinc/cms-component-library.git for the URL. This will use your global GitHub user keys setup during the sv-kubernetes setup.
4. Click the button labeled "OK" and wait for the repo to checkout. This will create a folder called cms-component-library at D:\cms30\cms-component-library.
- Example using terminal or Windows CMD:
1. In your terminal, navigate (or created as needed) to D:\cms30\ or ~/cms30 (this is the recommend folder location, but not required).
2. Execute git clone git@github.com:simpleviewinc/cms-component-library.git
`shell
cd D:/cms-30 # or whichever folder you are saving this in
git clone git@github.com:simpleviewinc/cms-component-library.git
`
3. Install Dependencies
1. Open CMD Prompt (or your terminal of choice) and cd to D:\cms30\cms-component-library: cd cms-component-library
2. Execute npm install
`shell
cd cms-component-library
npm install
`
4. Configure VS Code
1. Download the ESLint extension for VS Code.
2. Open your command palette (Ctrl+Shift+P on Windows and Cmd+Shift+P on Mac) and search for settings. Select the "Preferences: Open Settings (JSON)" option.
3. Add the following JSON block to your settings.json file:
`json
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
},
`
5. Start Storybook
Storybook is the main method of local testing.
1. Open CMD Prompt (or your terminal of choice) and cd to D:\cms30\cms-component-library: cd cms-component-library
2. Execute npm run storybook
3. Visit http://localhost:6006 on your local machine
`shell
cd cms-component-library
npm run storybook
`
Back to top
NPM Scripts
A list of the scripts available via package.json and their functions. Scripts are run via the command npm run [script]
- storybook: Starts up Storybook
- build-storybook: Builds storybook for production (GitHub Pages)
- code-quality: Run type-check, lint, and prettier
- type-check: Run TypeScript against all code to check for type errors
- lint: Lint all code, fix anything that can be fixed by eslint in the process
- prettier: Format all code, overwrite files
- test: Run all tests
- build: Build NPM Package to dist folder
- publish: Publish NPM release
Back to top
Repo Structure
- .storybook: Configuration for Storybook
- .vscode: Global snippets
- __MOCKS__: Jest mocks, used to stub out API or filesystem calls - [Learn More][Jest-Docs-manual-mocks]
- src: Main source code path
- index.tsx: Main export for NPM package, if a component is not exported here, it won't be in the NPM package (More on NPM below)
- components: React components and their corresponding CSS files
- ComponentName/ComponentName.tsx: The component itself
- ComponentName/ComponetName.spec.tsx: Tests for ComponentName component (More on tests below)
- ComponentName/ComponentName.stories.tsx: Stories for ComponentName componet. (More on stories below)
- ComponentName.module.css: CSS styles for ComponentName
- stories: Storybook Introduction and stories not tied to a component
- Introduction.stories.mdx: The intro page of storybook that outlines the storybook structure
- assets: Assets for the introduction story and others not tied to specific components
- documentation: Stories not tied to specific components, typically to display foundation styling
- styles: Global CSS files
- global.css: Globally scoped CSS
- normalize.css: Cross-browser default styles reboot
- foundations.css: Global CSS variables (will be replacing swatches.css in the future)
- swatches.css: Global CSS variables (formerly variables.css)
- hooks: Path for all custom hooks
- types: Path for all shared types
- lib: Old SV libraries converted to TypeScript
- utils: Generic re-usable utilities
- .eslintrc.yml: ESLint configuration
- .prettierrc: Prettier configuration
- jest.config.ts: Jest configuration
- jest.setup.ts: Jest setup (runs before all tests)
Back to top
Unit Testing
We use [Jest][Jest-Docs] and [React Testing Library][React-Testing-Library-Docs] to unit test every component. We also include [jest-axe][Jest-Axe-Docs] unit tests in every component test suite for basic accessibility coverage.
Unit tests are saved as ComponentName.spec.tsx
As an example of a basic test, here we are testing the Link component using the getByText query:
`js
import React from 'react';
import { render } from '@testing-library/react'; // react-testing-library
// We do not need to import Jest, when we run tests
// it is Jest that runs these files, so all Jest
// functions are implicit
import Link from '../Link'; // This is the component we are testing
import { axe, toHaveNoViolations } from 'jest-axe'; // Jest-axe provides basic testing for common accessibility issues
expect.extend(toHaveNoViolations); // This adds the jest-axe custom Jest matcher to check for accessibility issues
// We start with describe, we are describing our Link component
describe('Link Component', () => {
// We expect that it Renders Correctly, you can have
// multiple it blocks if your component is more complex
// and requires testing different scenarios
it('Renders Correctly', () => {
// Here we are defining some variables to use as props
// for the component
const to = {
url: 'https://simplevieweinc.com/',
target: '_blank',
};
const childText = 'test text';
// This is an extra prop, we also want to make sure they are tested,
// check the Link component to see where the extra props are passed
const rel = 'noopener noreferrer';
// We get any queries we want to use (getByText here) from the
// render function of react-testing-library, and pass in our
// component with the mock data above, check the documentation
// for react-testing-library for more available queries
const { getByText } = render(
to={to}
rel={rel}
>
{childText}
,
);
// We should see the test within childText in the rendered component
const linkElement = getByText(childText);
// We expect to have found the element rendered by our component
expect(linkElement).toBeDefined();
// We expect the target, href, and rel attributes to be
// added to the element as defined by the Link component. Check
// the Jest documentation for more on expect Matchers.
expect(linkElement).toHaveProperty('target', to.target);
expect(linkElement).toHaveProperty('href', to.url);
expect(linkElement).toHaveProperty('rel', rel);
});
// A version of this test is added to every compoonent's unit tests
// to ensure that there are no testable accessibility (a11y) violations
// utilizing jest-axe's .toHaveNoViolations().
it('should not have any testable a11y violations', async () => {
const { container } = render(
link={{
url: '/',
}}
data-testid='wrap-link-test'
>
Test Text
,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
`
Back to top
Stories
[Storybook][Storybook-Docs] is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation.
$3
We use Storybook to document our components. Storybook auto-generates documentation from comments in the component code, so it's crucial to add clear and contextual comments directly in the component files, not in the story files.
An example of the Docs page for the Link component
Here is an example showing the comments for the Link component's props that are automatically converted to Storybook Docs:
` js
export type LinkProps = {
/**
* The to object specifies the URL to link to, and optionally a target that specifies where to open the linked document.
*/
to: LinkAsset;
/**
* The target attribute specifies where to open the linked document, overriding the target key in the to object.
*/
target?: '_self' | '_blank' | '_parent' | '_top';
}
`
In the above code example, the LinkProps will automatically render like this:
!Storybook Link Props from 'https://simpleviewinc.github.io/cms-component-library/?path=/docs/ui-controls-link--docs'
> NOTE: In the above code example the comment / / that is directly above the prop is used in Storybook as documentation for that prop. Storybook will be able to auto-detect the type and default (most of the time).
After the props are declared, the component description should be added that explains the general purpose or function of the component as well as any helpful clarifications. This will also display at the top of the Storybook Doc.
Here's an example below of the comments for the Link component. If you visit the Link component in Storybook you can see these comments translated into the Link description at the top of the page.
` js
/**
* The Link component is used to trigger an action or event where the primary intention is navigation.
*
* The target property can be specified in two places, either as a property of the to object, or
* as a prop on the Link component itself. If both are specified, the to object is ignored.
* This way, you can override the target without modifing the to object.
*/
`
$3
Stories are saved as ComponentName.stories.tsx
Here is an example of a story for our Link component:
`js
import React from 'react';
import { Link } from '../components';
// The title here translates to the story Link in the UI Controls folder
export default {
title: 'UI Controls/Link',
component: Link,
};
// Render the Link component
const Template: StoryFn = (args) => {
const { children } = args;
return {children};
};
// Standard is a layout displayed in Storybook,
// we can define multiple layouts if needed (e.g. SecondStandard).
// The args passed to primary are the props
// that the rendered component will receive.
export const Standard = Template.bind({});
Standard.args = {
to: {
url: '/',
target: '_self',
},
target: '_self',
variant: 'link',
children: 'I am a link',
};
// SecondStandard is an additional layout displayed
// in Storybook, that uses the same Template as Standard,
// but with it's own unique props.
export const SecondStandard= Template.bind({});
Standard.args = {
to: {
url: '/',
target: '_blank',
},
target: '_blank',
variant: 'link',
children: 'I am a second link',
};
`
Back to top
NPM Package
See the NPM Release Documentation for instructions on deploying new versions to NPM.
Back to top
References and Resources
$3
We have included some helpful boilerplate snippets for VSCode users.
There are currently the following named snippets:
- svcomponent - the boilerplate for a new component
- svtest - the boilerplate for a new Jest test suite
- svstory - the boilerplate for a new Storybook story
To use these snippets:
1. Create the folder for the new component and the relating file (NewComponent.tsx, NewComponent.spec.tsx, NewComponent.stories.tsx respectively)
2. Type the snippet name in the body of the file and press Tab
3. The boilerplate should render and allow you to change the ComponentName`, if needed