-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
117 lines (103 loc) · 4.07 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import * as fs from "fs";
import { createMarkdownObjectTable, Stream } from 'parse-markdown-table'
import { Test } from '@japa/runner'
import getCallerFile from 'get-caller-file'
type Auth = { username: string, password: string }
export interface TranslatedRow {
[key: string]: any,
__rowProps: {
entity: any,
fromTable?: any,
auth: Auth
}
}
type DictionaryProps = { [key: string]: { field: string, domain: any } }
type Dictionary = (rows?: any) => Promise<DictionaryProps>
export interface TableProps {
tablePath?: string
extension?: string
dictionary?: Dictionary
authColumns?: Auth
}
export interface TableDrivenTestsConfig {
usernameHeader?: string
passwordHeader?: string
extension?: string
}
function translate(row: any, dictionary: DictionaryProps, { username, password }: Auth) {
let translatedRow: TranslatedRow = {
__rowProps: {
entity: {},
fromTable: {},
auth: { username: '', password: '' }
}
}
const props = translatedRow.__rowProps;
Object.entries(row).forEach(([rowHeader, rowValue]) => {
translatedRow[rowHeader] = rowValue;
props.fromTable[rowHeader] = rowValue
Object.entries(dictionary).forEach(([key, { field, domain }]) => {
if (rowHeader === key) {
translatedRow[key] = domain[row[key]];
if (field) props.entity[field] = domain[row[key]];
props.fromTable[key] = row[key]
}
if (key === username) props.auth.username = domain[row[key]]
if (key === password) props.auth.password = domain[row[key]]
})
})
return translatedRow
}
async function getTableValues(tablePath: string, extension: string) {
let untranslatedRows: any[] = [];
try {
const file: Stream = await fs.promises.readFile(tablePath.replace(extension, '.md'), 'utf-8')
const data = await createMarkdownObjectTable(file)
for await (const row of data) {
untranslatedRows.push(row)
}
return untranslatedRows;
} catch (error) {
console.log("Error when reading data from table ->", error)
}
}
async function dictionaryNotProvided(rows: any): Promise<DictionaryProps> {
return Object.keys(rows[0]).map(k => k).reduce((acc, key) => {
let fields: any = [...new Set(rows.map((row: any) => row[key]))];
return {
...acc,
...fields.reduce((obj: any, field: string) => {
if (obj[key]) {
return { [key]: { field: '', domain: { ...obj[key].domain, [field]: [field] } } }
} else {
return { [key]: { field: '', domain: { [field]: [field] } } }
}
}, {})
}
}, {})
}
async function createDictionary(dictionary: Dictionary, rows: any) {
try {
return await dictionary(rows);
} catch (error) {
console.log("Error when creating dictionary: ", error)
}
}
async function translateTestData({ tablePath, authColumns, dictionary, extension }: Required<TableProps>): Promise<TranslatedRow[]> {
const untranslatedRows = await getTableValues(tablePath, extension)
const translation = await createDictionary(dictionary, untranslatedRows);
if (!translation || !untranslatedRows) return [];
return untranslatedRows.map(row => translate(row, translation, authColumns))
}
export default function tableDrivenTests({ usernameHeader, passwordHeader, extension }: TableDrivenTestsConfig = {}) {
return async function (_: any, __: any, { Test }: { Test: any }) {
Test.macro('withTableData', function (this: Test<TranslatedRow[]>, {
dictionary = dictionaryNotProvided,
tablePath = getCallerFile(),
authColumns = { username: usernameHeader || 'Username', password: passwordHeader || 'Password' }
}: Omit<TableProps, 'extension'> = {}) {
return this.with(async () =>
await translateTestData({ tablePath, extension: extension || '.spec.ts', authColumns, dictionary }));
})
}
}