Skip to content

Commit

Permalink
feat: data driven testing ui
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed May 12, 2021
1 parent 54a0af6 commit 4684b95
Show file tree
Hide file tree
Showing 21 changed files with 408 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
"name": "jest instrument",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"cwd": "${workspaceFolder}/core/instrument",
"args": ["jest-tests"],
"args": ["data-driven"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
Expand Down
17 changes: 16 additions & 1 deletion core/core/src/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export type Story<Props = any> = {
*/
id?: string;

/**
* raw id for the story as declared in ESM format
*/
rawId?: string;
/**
* title of the file/group of stories
*/
Expand Down Expand Up @@ -129,8 +133,10 @@ export type Story<Props = any> = {

export type DynamicExamples = Story[];

export type ExampleControl = ComponentControl<ExampleControls> | any;

export type ExampleControls = {
[name: string]: ComponentControl<ExampleControls> | any;
[name: string]: ExampleControl;
};

/**
Expand All @@ -146,6 +152,10 @@ export type Example<Props = any> = {
controls?: ExampleControls;
};

/**
* records of storyid/data pairs, to be associated with documents
*/
export type DocumentData = Record<string, ExampleControls>;
/**
* dynamic story creator function type.
* returns an array of dynamically loaded stories
Expand Down Expand Up @@ -265,6 +275,11 @@ export type Document<Props = any> = {
* optional test data file
*/
testData?: string;

/**
* loaded data associated with the document
*/
data?: DocumentData;
/**
* lookup into the global store.components
* since multiple components of the same name can be used
Expand Down
5 changes: 5 additions & 0 deletions core/core/src/node-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ export const resolveSnapshotFile = (testFilePath: string): string =>
'__snapshots__',
`${path.basename(testFilePath)}.snap`,
);

export const relativeImport = (from: string, to: string): string => {
const relative = path.relative(from, to);
return relative.startsWith('.') ? relative : `./${relative}`;
};
30 changes: 18 additions & 12 deletions core/instrument/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ import {
defaultMDXOptions,
ParseStorieReturnType,
} from './types';
import { assignDocumentData } from './misc/data-driven';

export * from './types';

export { getDataFile } from './misc/data-driven';

export { prettify };

type TraverseFn = (
Expand Down Expand Up @@ -88,19 +91,22 @@ const parseSource = async (
}
await extractStoreComponent(store, filePath, source, options);
const doc: Document | undefined = store.doc;
if (doc && store.stories) {
const storyPackage = await packageInfo(
doc.title,
filePath,
options.stories.package,
);
if (storyPackage) {
store.packages[storyPackage.fileHash] = storyPackage;
doc.package = storyPackage.fileHash;
if (doc) {
assignDocumentData(doc, filePath);
if (store.stories) {
const storyPackage = await packageInfo(
doc.title,
filePath,
options.stories.package,
);
if (storyPackage) {
store.packages[storyPackage.fileHash] = storyPackage;
doc.package = storyPackage.fileHash;
}
const dates = await getFileDates(filePath);
doc.dateModified = doc.dateModified || dates.dateModified;
doc.date = doc.date || dates.dateCreated;
}
const dates = await getFileDates(filePath);
doc.dateModified = doc.dateModified || dates.dateModified;
doc.date = doc.date || dates.dateCreated;
}
for (const key of Object.keys(store.stories)) {
const story: Story = store.stories[key];
Expand Down
49 changes: 49 additions & 0 deletions core/instrument/src/misc/data-driven.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import path from 'path';
import fs from 'fs';
import {
dynamicRequire,
relativeImport,
} from '@component-controls/core/node-utils';
import { DocumentData, Document } from '@component-controls/core';
import { CachedFileResource } from './chached-file';

export const getDataFile = (filePath: string): string => {
const parts = filePath.split('.');
parts.splice(
parts.length - parts.length <= 2 ? 1 : 2,
parts.length <= 2 ? 0 : 1,
'data',
);
const extention = parts[parts.length - 1];
if (extention.length === 3) {
parts[parts.length - 1] = extention.slice(0, -1);
}
return parts.join('.');
};

export const assignDocumentData = (doc: Document, filePath: string): void => {
const dataFilePath = doc.testData
? path.resolve(path.dirname(filePath), doc.testData)
: getDataFile(filePath);

if (fs.existsSync(dataFilePath)) {
const cached = new CachedFileResource<DocumentData>(
'data-driven',
`v1`,
filePath,
);
let result: DocumentData | undefined = cached.get();
if (result) {
doc.data = result;
doc.testData =
doc.testData || relativeImport(path.dirname(filePath), dataFilePath);
return;
}
//load existing data file
const loaded = dynamicRequire(dataFilePath);
result = loaded.default || loaded;
cached.set(result);
doc.data = result;
doc.testData = doc.testData || path.relative(filePath, dataFilePath);
}
};
43 changes: 43 additions & 0 deletions core/instrument/test/data-driven.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import path from 'path';
import { Document } from '@component-controls/core';
import { getDataFile, assignDocumentData } from '../src/misc/data-driven';

describe('data-driven', () => {
it('getDataFile length 1', () => {
const fileName = getDataFile('file');
expect(fileName).toBe('file.data');
});
it('getDataFile length 2', () => {
const fileName = getDataFile('file.js');
expect(fileName).toBe('file.data.js');
});

it('getDataFile length > 2', () => {
const fileName = getDataFile('file.test.js');
expect(fileName).toBe('file.data.js');
});
it('load data file', () => {
const doc: Document = { title: 'doc' };
assignDocumentData(
doc,
path.resolve(
__dirname,
'../../../examples/stories/src/stories/VariantButton/VariantButton.stories.tsx',
),
);
expect(doc.testData).toBe('./VariantButton.data.ts');
expect(Object.keys(doc.data?.overview).length).toBe(5);
});
it('load doc testData file', () => {
const doc: Document = { title: 'doc', testData: './VariantButton.data.ts' };
assignDocumentData(
doc,
path.resolve(
__dirname,
'../../../examples/stories/src/stories/VariantButton/VariantButton.stories.tsx',
),
);
expect(doc.testData).toBe('./VariantButton.data.ts');
expect(Object.keys(doc.data?.overview).length).toBe(5);
});
});
1 change: 1 addition & 0 deletions core/store/src/serialization/load-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const loadStore = (store: LoadingStore, building?: boolean): Store => {
const story = {
...docStory,
id: docStoryToId(doc.title, id),
rawId: id,
name: storyNameFromExport(docStory.name),
doc: doc.title,
};
Expand Down
8 changes: 6 additions & 2 deletions core/store/src/state/context/document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getHomePath,
getComponentName,
SearchResult,
CURRENT_STORY,
} from '@component-controls/core';
import { useStore, useActiveTab } from './store';

Expand All @@ -30,9 +31,12 @@ export const DocumentContextProvider: FC<{ docId: string | undefined }> = ({
/**
* Retrieves a Document object from a document id
*/
export const useDocument = (docId?: string): Document | undefined => {
export const useDocument = (
docId: string = CURRENT_STORY,
): Document | undefined => {
const store = useStore();
return docId ? store.docs[docId] : undefined;
const current = useCurrentDocument();
return docId === CURRENT_STORY ? current : store.docs[docId];
};

export const useGetDocument = (): ((docId: string) => Document | undefined) => {
Expand Down
24 changes: 14 additions & 10 deletions plugins/cc-cli/src/cli/save-data-template.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import path from 'path';
import fs from 'fs';
import { dynamicRequire } from '@component-controls/core/node-utils';
import {
dynamicRequire,
relativeImport,
} from '@component-controls/core/node-utils';
import { getDataFile } from '@component-controls/instrument';

import { log } from '@component-controls/logger';
import { CliOptions, getTestFolder } from './utils';
import { TemplateOptions, DataImportOptions, relativeImport } from '../utils';
import { TemplateOptions, DataImportOptions } from '../utils';
import { createDataTemplate } from '../data-templates/data-template';

/**
Expand All @@ -18,10 +23,7 @@ export const saveDataTemplate = async <P extends TemplateOptions>(
return undefined;
}
const { test, overwrite } = options;
const dataName = test
.split('.')
.map((e, i) => (i === 1 ? 'data' : e))
.join('.');
const dataName = getDataFile(test);

const filePath = path.resolve(testFolder, dataName);

Expand All @@ -37,11 +39,13 @@ export const saveDataTemplate = async <P extends TemplateOptions>(
}
const dataTemplate = await createDataTemplate(options, existing);
if (dataTemplate) {
log('saving data', filePath, [184, 226, 255]);
if (!fs.existsSync(testFolder)) {
fs.mkdirSync(testFolder);
if (dataTemplate.isModified) {
log('saving data', filePath, [184, 226, 255]);
if (!fs.existsSync(testFolder)) {
fs.mkdirSync(testFolder);
}
fs.writeFileSync(filePath, dataTemplate.content, 'utf8');
}
fs.writeFileSync(filePath, dataTemplate.content, 'utf8');
return {
data: dataTemplate.data,
filePath: relativeImport(testFolder, filePath),
Expand Down
8 changes: 7 additions & 1 deletion plugins/cc-cli/src/data-templates/data-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import { getTemplate } from '../resolve-template';
export const createDataTemplate = async (
options: StoryTemplateOptions,
existing?: Record<string, any>,
): Promise<{ content: string; data: Record<string, any> } | undefined> => {
): Promise<
| { content: string; data: Record<string, any>; isModified: boolean }
| undefined
> => {
const {
name,
bundle,
Expand All @@ -37,6 +40,7 @@ export const createDataTemplate = async (
}
const { doc, stories, components } = parsed;
const data: Record<string, any> = {};
let isModified = false;
Object.keys(stories).forEach(storyId => {
const story = stories[storyId];

Expand All @@ -47,6 +51,7 @@ export const createDataTemplate = async (
for (let i = Object.keys(values).length; i < numValues; i += 1) {
const rnd = randomizeData(controls);
if (Object.keys(rnd).length) {
isModified = true;
values[i.toString()] = rnd;
}
}
Expand All @@ -59,6 +64,7 @@ export const createDataTemplate = async (
return undefined;
}
return {
isModified,
content: prettify(
dot.template(getTemplate(`data-templates/data`, format))({
data: JSON.stringify(data, null, 2),
Expand Down
2 changes: 1 addition & 1 deletion plugins/cc-cli/src/jest-templates/document-template.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import path from 'path';
import dot from 'dot';
import { relativeImport } from '@component-controls/core/node-utils';
import { createTemplate } from './template';
import { accessibilityTemplate } from './accessibily';
import {
StoryTemplateOptions,
renderers,
TemplateFunction,
DataImportOptions,
relativeImport,
removeExtension,
} from '../utils';
import { getTemplate } from '../resolve-template';
Expand Down
2 changes: 1 addition & 1 deletion plugins/cc-cli/src/jest-templates/stories-template.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import path from 'path';
import dot from 'dot';
import { relativeImport } from '@component-controls/core/node-utils';
import { createTemplate } from './template';
import { accessibilityTemplate } from './accessibily';
import {
StoryTemplateOptions,
renderers,
TemplateFunction,
DataImportOptions,
relativeImport,
removeExtension,
} from '../utils';
import { getTemplate } from '../resolve-template';
Expand Down
7 changes: 5 additions & 2 deletions plugins/cc-cli/src/jest-templates/template.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import path from 'path';
import dot from 'dot';
import { defaultConfigFolder } from '@component-controls/core/node-utils';
import {
defaultConfigFolder,
relativeImport,
} from '@component-controls/core/node-utils';
import { prettify } from '@component-controls/instrument';
import { accessibilityTemplate } from './accessibily';
import { TemplateOptions, renderers, relativeImport } from '../utils';
import { TemplateOptions, renderers } from '../utils';
import { getTemplate } from '../resolve-template';
dot.templateSettings.strip = false;
(dot as any).log = false;
Expand Down
6 changes: 0 additions & 6 deletions plugins/cc-cli/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import path from 'path';
export const renderers = {
rtl: 'react-testing-library',
rtr: 'react-test-renderer',
Expand Down Expand Up @@ -62,11 +61,6 @@ export interface DataImportOptions {
data: Record<string, any>;
}

export const relativeImport = (from: string, to: string): string => {
const relative = path.relative(from, to);
return relative.startsWith('.') ? relative : `./${relative}`;
};

export const formatExtension = (format: TeplateFormats): string =>
format === 'ts' ? 'ts' : 'js';

Expand Down
4 changes: 2 additions & 2 deletions ui/blocks/src/Stories/Stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FC } from 'react';
import {
useStory,
useCurrentDocument,
useDocument,
StoryInputProps,
useStore,
} from '@component-controls/store';
Expand All @@ -25,7 +25,7 @@ export type StoriesProps = StoriesOwnProps &
*/
export const Stories: FC<StoriesProps> = ({ id, name, title, ...rest }) => {
const story = useStory({ id, name });
const doc = useCurrentDocument();
const doc = useDocument(story?.doc);
const store = useStore();
const stories = doc?.stories
? doc.stories.filter((id: string) => !story || story.id !== id)
Expand Down
Loading

0 comments on commit 4684b95

Please sign in to comment.