From 0bb4343ae6cee25ca9fe45436b7421a76ae87f6d Mon Sep 17 00:00:00 2001 From: JQQQ Date: Wed, 20 Jan 2021 17:45:15 +1300 Subject: [PATCH 1/3] [SKIP CI] tidy up --- packages/cli/base.graphql | 6 -- packages/cli/docker-compose.yml | 11 --- packages/cli/schema.graphql | 13 ---- .../src/controller/codegen-controller.spec.ts | 56 +++++++++++++++ .../src/controller/codegen-controller.test.ts | 69 +++++++++++++++++++ .../cli/src/controller/codegen-controller.ts | 49 +++++++------ .../src/controller/init-controller.spec.ts | 28 ++++---- packages/cli/src/controller/types-mapping.ts | 5 +- packages/cli/test.sh | 1 - packages/cli/test/badschema.graphql | 15 ++++ packages/cli/test/schema.graphql | 12 ++++ 11 files changed, 199 insertions(+), 66 deletions(-) delete mode 100644 packages/cli/base.graphql delete mode 100644 packages/cli/docker-compose.yml delete mode 100644 packages/cli/schema.graphql create mode 100644 packages/cli/src/controller/codegen-controller.spec.ts create mode 100644 packages/cli/src/controller/codegen-controller.test.ts delete mode 100644 packages/cli/test.sh create mode 100644 packages/cli/test/badschema.graphql create mode 100644 packages/cli/test/schema.graphql diff --git a/packages/cli/base.graphql b/packages/cli/base.graphql deleted file mode 100644 index 4d14ae7539..0000000000 --- a/packages/cli/base.graphql +++ /dev/null @@ -1,6 +0,0 @@ -scalar BigInt -scalar BigDecimal -scalar Bytes - -directive @derivedFrom(field: String!) on FIELD_DEFINITION -directive @entity on OBJECT diff --git a/packages/cli/docker-compose.yml b/packages/cli/docker-compose.yml deleted file mode 100644 index ea72a0237c..0000000000 --- a/packages/cli/docker-compose.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: '3' - -services: - postgres: - image: postgres:12-alpine - ports: - - 5432:5432 - volumes: - - .data/postgres:/var/lib/postgresql/data - environment: - POSTGRES_PASSWORD: postgres diff --git a/packages/cli/schema.graphql b/packages/cli/schema.graphql deleted file mode 100644 index 3ecd2c3e88..0000000000 --- a/packages/cli/schema.graphql +++ /dev/null @@ -1,13 +0,0 @@ -type Extrinsic @entity { - id: ID! - - NumExtrinsic: Int! -} - -type testEntity @entity { - id: ID! - - NumExtrinsic: Int! - - NumEvent: Int -} diff --git a/packages/cli/src/controller/codegen-controller.spec.ts b/packages/cli/src/controller/codegen-controller.spec.ts new file mode 100644 index 0000000000..b90c5a3374 --- /dev/null +++ b/packages/cli/src/controller/codegen-controller.spec.ts @@ -0,0 +1,56 @@ +import fs from 'fs'; +import ejs from 'ejs'; +import {makeSchema, renderTemplate, generateSchema} from './codegen-controller'; +jest.mock('fs', () => { + const fsMock = jest.createMockFromModule('fs') as any; + fsMock.promises = { + writeFile: jest.fn(), + access: jest.fn(), + }; + fsMock.readFileSync = jest.fn(); + return fsMock; +}); + +jest.mock('ejs', () => { + const ejsMock = jest.createMockFromModule('ejs') as any; + ejsMock.renderFile = jest.fn(); + return ejsMock; +}); + +const mockedTemplate = { + props: { + baseFolderPath: 'some_dir_path', + className: 'randomClass', + fields: ['field1', 'field2'], + }, +}; + +describe('Codegen can generate schema (mocked fs)', () => { + it('should throw error when write schema file failed', async () => { + (fs.promises.access as jest.Mock).mockImplementation(() => Promise.resolve()); + (fs.promises.writeFile as jest.Mock).mockImplementation(() => Promise.reject(new Error('write failed'))); + await expect(makeSchema('classname', 'random data')).rejects.toThrow(/write failed/); + }); + + it('write schema should pass', async () => { + (fs.promises.access as jest.Mock).mockImplementation(() => Promise.resolve()); + (fs.promises.writeFile as jest.Mock).mockImplementation(() => Promise.resolve()); + await expect(makeSchema('classname', 'random data')).resolves; + }); + + it('render ejs template with an incorrect format modelTemplate should throw', async () => { + (ejs.renderFile as jest.Mock).mockImplementation(() => Promise.reject(new Error('render template failed'))); + await expect(renderTemplate('renderTemplateTest', mockedTemplate)).rejects.toThrow(/render template failed/); + }); + + it('render ejs template with correct format modelTemplate should pass', async () => { + (ejs.renderFile as jest.Mock).mockImplementation(() => Promise.resolve()); + await expect(renderTemplate('renderTemplateTest', mockedTemplate)).resolves; + }); + + it('generate schema should pass', async () => { + const schemaString = 'type goodEntity @entity {id: ID!}'; + (fs.readFileSync as jest.Mock).mockReturnValue(schemaString); + await expect(generateSchema()).resolves; + }); +}); diff --git a/packages/cli/src/controller/codegen-controller.test.ts b/packages/cli/src/controller/codegen-controller.test.ts new file mode 100644 index 0000000000..530c0d5f1d --- /dev/null +++ b/packages/cli/src/controller/codegen-controller.test.ts @@ -0,0 +1,69 @@ +import {getAllEntities, buildSchema} from '@subql/common'; +import {transformTypes} from './types-mapping'; +import {processFields, renderTemplate, makeSchema, generateSchema} from './codegen-controller'; +import path from 'path'; +import os from 'os'; +import fs from 'fs'; + +async function makeTempDir(): Promise { + const sep = path.sep; + const tmpDir = os.tmpdir(); + return fs.mkdtempSync(`${tmpDir}${sep}`); +} + +describe('Codegen can generate schema', () => { + const badschema = buildSchema(path.join(__dirname, '../../test/badschema.graphql')); + const badextractEntities = getAllEntities(badschema); + const goodschema = buildSchema(path.join(__dirname, '../../test/schema.graphql')); + const goodextractEntities = getAllEntities(goodschema); + const sep = path.sep; + const tmpDir = os.tmpdir(); + const tempPath = fs.mkdtempSync(`${tmpDir}${sep}`); + + it('can transform field into correct type', () => { + const testClassName = 'transformTest;'; + expect(transformTypes(testClassName, 'ID')).toBe('string'); + expect(transformTypes(testClassName, 'Int')).toBe('number'); + expect(transformTypes(testClassName, 'BigInt')).toBe('bigint'); + expect(transformTypes(testClassName, 'String')).toBe('string'); + expect(transformTypes(testClassName, 'Date')).toBe('Date'); + }); + + it('process field with correct types should pass', () => { + const testClassName = 'processFieldTest'; + expect.assertions(1); + for (const entity of goodextractEntities) { + const fields = entity.getFields(); + const fieldList = processFields(testClassName, fields); + expect(fieldList).toBeDefined(); + } + }); + + it('process field with unknown type to throw', () => { + const testClassName = 'processFieldTest'; + expect.assertions(1); + for (const entity of badextractEntities) { + const fields = entity.getFields(); + expect(() => processFields(testClassName, fields)).toThrow(); + //Float in badschema is not support, should throw error + } + }); + + it('save schema to a empty project directory should fail', async () => { + const testClassName = 'makeSchemaTest'; + const tempPath = await makeTempDir(); + process.chdir(tempPath); + await expect(makeSchema('classname', 'random data')).rejects.toThrow( + /Write schema to file failed, check project directory is correct/ + ); + }); + + it('save schema to a correct project directory should pass', async () => { + const testClassName = 'makeSchemaTest2'; + const tempPath = await makeTempDir(); + process.chdir(tempPath); + fs.mkdir('src/types/models', {recursive: true}, (err) => { + expect(makeSchema(testClassName, 'random text to add to schema')).resolves.not.toThrow(); + }); + }); +}); diff --git a/packages/cli/src/controller/codegen-controller.ts b/packages/cli/src/controller/codegen-controller.ts index cba8b5337d..a342bb271e 100644 --- a/packages/cli/src/controller/codegen-controller.ts +++ b/packages/cli/src/controller/codegen-controller.ts @@ -8,33 +8,37 @@ import ejs from 'ejs'; import {isNonNullType, getNullableType} from 'graphql'; import {GraphQLFieldMap, GraphQLOutputType} from 'graphql/type/definition'; import {transformTypes} from './types-mapping'; + const templatePath: string = path.resolve(__dirname, '../template/model.ts.ejs'); -const typesPath = `${process.cwd()}/src/types/models`; // 4. Save the rendered schema -function makeSchema(className: string, data: string): void { +export async function makeSchema(className: string, data: string): Promise { + const typesPath = `${process.cwd()}/src/types/models`; const filename = `${className}.ts`; const file = `${typesPath}/${filename}`; - fs.writeFile(file, data, (err) => { - if (err) { - console.error(err); - return; - } - console.log(`>--- Schema ${className} generated !`); - }); + try { + await fs.promises.access(typesPath); + } catch (err) { + throw new Error('Write schema to file failed, check project directory is correct'); + } + + try { + await fs.promises.writeFile(file, data); + } catch (err) { + throw new Error(err.message); + } + console.log(`>--- Schema ${className} generated !`); } // 3. Render entity data in ejs template -export function renderTemplate(className: string, modelTemplate: ejs.Data): void { - ejs.renderFile(templatePath, modelTemplate, function (err, str) { - if (err) { - console.log(`!!! When render entity ${className} to schema have following problems !!! `); - console.log(err); - } else { - makeSchema(className, str); - } - }); +export async function renderTemplate(className: string, modelTemplate: ejs.Data): Promise { + try { + const renderedFilePath = await ejs.renderFile(templatePath, modelTemplate); + await makeSchema(className, renderedFilePath); + } catch (err) { + throw new Error(err.message); + } } // 2. Re-format the field of the entity @@ -50,6 +54,10 @@ export function processFields(className: string, fields: GraphQLFieldMap { const schema = buildSchema('./schema.graphql'); const extractEntities = getAllEntities(schema); - for (const entity of extractEntities) { const baseFolderPath = '.../../base'; const className = entity.name; @@ -78,6 +85,6 @@ export function generateSchema(): void { }, }; console.log(`<--- Start generate schema ${modelTemplate.props.className}`); - renderTemplate(className, modelTemplate); + await renderTemplate(className, modelTemplate); } } diff --git a/packages/cli/src/controller/init-controller.spec.ts b/packages/cli/src/controller/init-controller.spec.ts index 58562e0498..310cef5d79 100644 --- a/packages/cli/src/controller/init-controller.spec.ts +++ b/packages/cli/src/controller/init-controller.spec.ts @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import * as fs from 'fs'; -import rimraf from 'rimraf'; -import {createProject} from './init-controller'; - +import path from 'path'; +import os from 'os'; const projectName = 'mockStarterProject'; +import {createProject} from './init-controller'; // async const fileExists = async (file) => { @@ -16,27 +16,31 @@ const fileExists = async (file) => { }); }; -describe('Cli can create project', () => { - beforeEach(async () => { - await new Promise((resolve) => rimraf(`${projectName}`, resolve)); - }); - - afterEach(async () => { - await new Promise((resolve) => rimraf(`${projectName}`, resolve)); - }); +async function makeTempDir(): Promise { + const sep = path.sep; + const tmpDir = os.tmpdir(); + return fs.mkdtempSync(`${tmpDir}${sep}`); +} +describe('Cli can create project', () => { it('should resolves when starter project successful created', async () => { + const tempPath = await makeTempDir(); + process.chdir(tempPath); await createProject(projectName); await expect(fileExists(`./${projectName}`)).resolves.toEqual(true); }); it('throw error if same name directory exists', async () => { + const tempPath = await makeTempDir(); + process.chdir(tempPath); fs.mkdirSync(`./${projectName}`); await expect(createProject(projectName)).rejects.toThrow(); }); it('throw error if .git exists in starter project', async () => { + const tempPath = await makeTempDir(); + process.chdir(tempPath); await createProject(projectName); - await expect(fileExists(`./${projectName}/.git`)).rejects.toThrow(); + await expect(fileExists(`${tempPath}/${projectName}/.git`)).rejects.toThrow(); }); }); diff --git a/packages/cli/src/controller/types-mapping.ts b/packages/cli/src/controller/types-mapping.ts index 987cabcb83..5b1c3838d1 100644 --- a/packages/cli/src/controller/types-mapping.ts +++ b/packages/cli/src/controller/types-mapping.ts @@ -9,8 +9,9 @@ typeMap.set('Int', 'number'); typeMap.set('BigInt', 'bigint'); typeMap.set('String', 'string'); typeMap.set('Date', 'Date'); -typeMap.set('Float', 'number'); -typeMap.set('BigDecimal', 'number'); +// TODO +// typeMap.set('Float', 'number'); +// typeMap.set('BigDecimal', 'number'); export function transformTypes(className: string, fieldType: string): string { const trimType = fieldType.trim(); diff --git a/packages/cli/test.sh b/packages/cli/test.sh deleted file mode 100644 index 465d17c19d..0000000000 --- a/packages/cli/test.sh +++ /dev/null @@ -1 +0,0 @@ -node --require ts-node/register/transpile-only --experimental-repl-await diff --git a/packages/cli/test/badschema.graphql b/packages/cli/test/badschema.graphql new file mode 100644 index 0000000000..3af85954b6 --- /dev/null +++ b/packages/cli/test/badschema.graphql @@ -0,0 +1,15 @@ +type badEntity @entity { + + id: ID! #id is a required field + + field1: Int! + + field2: String #filed2 is an optional field + + field3: BigInt + + field4: Date + + field5: Float + +} diff --git a/packages/cli/test/schema.graphql b/packages/cli/test/schema.graphql new file mode 100644 index 0000000000..f53740b835 --- /dev/null +++ b/packages/cli/test/schema.graphql @@ -0,0 +1,12 @@ +type goodEntity @entity { + + id: ID! #id is a required field + + field1: Int! + + field2: String #filed2 is an optional field + + field3: BigInt + + field4: Date +} From e0aab50f89c4443fcc7555dec6945e0be77bf7d8 Mon Sep 17 00:00:00 2001 From: JQQQ Date: Wed, 20 Jan 2021 23:13:08 +1300 Subject: [PATCH 2/3] [SKIP CI] fix code for lint --- .../src/controller/codegen-controller.spec.ts | 28 ++++++++++----- .../src/controller/codegen-controller.test.ts | 34 +++++++------------ .../cli/src/controller/codegen-controller.ts | 4 +-- .../src/controller/init-controller.spec.ts | 19 ++++++----- packages/cli/test/badschema.graphql | 13 +------ 5 files changed, 44 insertions(+), 54 deletions(-) diff --git a/packages/cli/src/controller/codegen-controller.spec.ts b/packages/cli/src/controller/codegen-controller.spec.ts index b90c5a3374..3e9a2d5404 100644 --- a/packages/cli/src/controller/codegen-controller.spec.ts +++ b/packages/cli/src/controller/codegen-controller.spec.ts @@ -1,3 +1,6 @@ +// Copyright 2020-2021 OnFinality Limited authors & contributors +// SPDX-License-Identifier: Apache-2.0 + import fs from 'fs'; import ejs from 'ejs'; import {makeSchema, renderTemplate, generateSchema} from './codegen-controller'; @@ -26,31 +29,38 @@ const mockedTemplate = { }; describe('Codegen can generate schema (mocked fs)', () => { + it('write schema to a empty project directory should fail', async () => { + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.reject(new Error())); + await expect(makeSchema('classname', 'random data')).rejects.toThrow( + 'Write schema failed, not in project directory' + ); + }); + it('should throw error when write schema file failed', async () => { - (fs.promises.access as jest.Mock).mockImplementation(() => Promise.resolve()); - (fs.promises.writeFile as jest.Mock).mockImplementation(() => Promise.reject(new Error('write failed'))); + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); + (fs.promises.writeFile as jest.Mock).mockImplementation(async () => Promise.reject(new Error('write failed'))); await expect(makeSchema('classname', 'random data')).rejects.toThrow(/write failed/); }); it('write schema should pass', async () => { - (fs.promises.access as jest.Mock).mockImplementation(() => Promise.resolve()); - (fs.promises.writeFile as jest.Mock).mockImplementation(() => Promise.resolve()); - await expect(makeSchema('classname', 'random data')).resolves; + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); + (fs.promises.writeFile as jest.Mock).mockImplementation(async () => Promise.resolve()); + await expect(makeSchema('classname', 'random data')).resolves.not.toThrow(); }); it('render ejs template with an incorrect format modelTemplate should throw', async () => { - (ejs.renderFile as jest.Mock).mockImplementation(() => Promise.reject(new Error('render template failed'))); + (ejs.renderFile as jest.Mock).mockImplementation(async () => Promise.reject(new Error('render template failed'))); await expect(renderTemplate('renderTemplateTest', mockedTemplate)).rejects.toThrow(/render template failed/); }); it('render ejs template with correct format modelTemplate should pass', async () => { - (ejs.renderFile as jest.Mock).mockImplementation(() => Promise.resolve()); - await expect(renderTemplate('renderTemplateTest', mockedTemplate)).resolves; + (ejs.renderFile as jest.Mock).mockImplementation(async () => Promise.resolve()); + await expect(renderTemplate('renderTemplateTest', mockedTemplate)).resolves.not.toThrow(); }); it('generate schema should pass', async () => { const schemaString = 'type goodEntity @entity {id: ID!}'; (fs.readFileSync as jest.Mock).mockReturnValue(schemaString); - await expect(generateSchema()).resolves; + await expect(generateSchema()).resolves.not.toThrow(); }); }); diff --git a/packages/cli/src/controller/codegen-controller.test.ts b/packages/cli/src/controller/codegen-controller.test.ts index 530c0d5f1d..5db21bb395 100644 --- a/packages/cli/src/controller/codegen-controller.test.ts +++ b/packages/cli/src/controller/codegen-controller.test.ts @@ -1,14 +1,18 @@ +// Copyright 2020-2021 OnFinality Limited authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import fs from 'fs'; +import os from 'os'; +import path from 'path'; import {getAllEntities, buildSchema} from '@subql/common'; +import {processFields, makeSchema} from './codegen-controller'; import {transformTypes} from './types-mapping'; -import {processFields, renderTemplate, makeSchema, generateSchema} from './codegen-controller'; -import path from 'path'; -import os from 'os'; -import fs from 'fs'; -async function makeTempDir(): Promise { +async function makeTempDir() { const sep = path.sep; const tmpDir = os.tmpdir(); - return fs.mkdtempSync(`${tmpDir}${sep}`); + const tempPath = await fs.promises.mkdtemp(`${tmpDir}${sep}`); + return tempPath; } describe('Codegen can generate schema', () => { @@ -16,9 +20,6 @@ describe('Codegen can generate schema', () => { const badextractEntities = getAllEntities(badschema); const goodschema = buildSchema(path.join(__dirname, '../../test/schema.graphql')); const goodextractEntities = getAllEntities(goodschema); - const sep = path.sep; - const tmpDir = os.tmpdir(); - const tempPath = fs.mkdtempSync(`${tmpDir}${sep}`); it('can transform field into correct type', () => { const testClassName = 'transformTest;'; @@ -41,7 +42,6 @@ describe('Codegen can generate schema', () => { it('process field with unknown type to throw', () => { const testClassName = 'processFieldTest'; - expect.assertions(1); for (const entity of badextractEntities) { const fields = entity.getFields(); expect(() => processFields(testClassName, fields)).toThrow(); @@ -49,21 +49,11 @@ describe('Codegen can generate schema', () => { } }); - it('save schema to a empty project directory should fail', async () => { - const testClassName = 'makeSchemaTest'; - const tempPath = await makeTempDir(); - process.chdir(tempPath); - await expect(makeSchema('classname', 'random data')).rejects.toThrow( - /Write schema to file failed, check project directory is correct/ - ); - }); - it('save schema to a correct project directory should pass', async () => { const testClassName = 'makeSchemaTest2'; const tempPath = await makeTempDir(); process.chdir(tempPath); - fs.mkdir('src/types/models', {recursive: true}, (err) => { - expect(makeSchema(testClassName, 'random text to add to schema')).resolves.not.toThrow(); - }); + await fs.promises.mkdir('src/types/models', {recursive: true}); + await expect(makeSchema(testClassName, 'random text to add to schema')).resolves.not.toThrow(); }); }); diff --git a/packages/cli/src/controller/codegen-controller.ts b/packages/cli/src/controller/codegen-controller.ts index a342bb271e..29edbf86aa 100644 --- a/packages/cli/src/controller/codegen-controller.ts +++ b/packages/cli/src/controller/codegen-controller.ts @@ -20,7 +20,7 @@ export async function makeSchema(className: string, data: string): Promise try { await fs.promises.access(typesPath); } catch (err) { - throw new Error('Write schema to file failed, check project directory is correct'); + throw new Error('Write schema failed, not in project directory'); } try { @@ -55,7 +55,7 @@ export function processFields(className: string, fields: GraphQLFieldMap { }); }; -async function makeTempDir(): Promise { +async function makeTempDir() { const sep = path.sep; const tmpDir = os.tmpdir(); - return fs.mkdtempSync(`${tmpDir}${sep}`); + const tempPath = await fs.promises.mkdtemp(`${tmpDir}${sep}`); + return tempPath; } describe('Cli can create project', () => { it('should resolves when starter project successful created', async () => { - const tempPath = await makeTempDir(); - process.chdir(tempPath); + const tempPath = makeTempDir(); + process.chdir(await tempPath); await createProject(projectName); await expect(fileExists(`./${projectName}`)).resolves.toEqual(true); }); it('throw error if same name directory exists', async () => { - const tempPath = await makeTempDir(); - process.chdir(tempPath); + const tempPath = makeTempDir(); + process.chdir(await tempPath); fs.mkdirSync(`./${projectName}`); await expect(createProject(projectName)).rejects.toThrow(); }); it('throw error if .git exists in starter project', async () => { - const tempPath = await makeTempDir(); - process.chdir(tempPath); + const tempPath = makeTempDir(); + process.chdir(await tempPath); await createProject(projectName); await expect(fileExists(`${tempPath}/${projectName}/.git`)).rejects.toThrow(); }); diff --git a/packages/cli/test/badschema.graphql b/packages/cli/test/badschema.graphql index 3af85954b6..3c25326e6b 100644 --- a/packages/cli/test/badschema.graphql +++ b/packages/cli/test/badschema.graphql @@ -1,15 +1,4 @@ type badEntity @entity { - id: ID! #id is a required field - - field1: Int! - - field2: String #filed2 is an optional field - - field3: BigInt - - field4: Date - - field5: Float - + id: Float #give the unknown type } From f0e0202dcac7f5aef23f6920582d3f4d1c355d87 Mon Sep 17 00:00:00 2001 From: JQQQ Date: Thu, 21 Jan 2021 12:15:52 +1300 Subject: [PATCH 3/3] [SKIP CI] Update cli test and codegen --- .../src/controller/codegen-controller.spec.ts | 48 ++++++++----------- .../src/controller/codegen-controller.test.ts | 19 +------- .../cli/src/controller/codegen-controller.ts | 18 ++++--- .../src/controller/init-controller.spec.ts | 4 +- 4 files changed, 32 insertions(+), 57 deletions(-) diff --git a/packages/cli/src/controller/codegen-controller.spec.ts b/packages/cli/src/controller/codegen-controller.spec.ts index 3e9a2d5404..b1906248be 100644 --- a/packages/cli/src/controller/codegen-controller.spec.ts +++ b/packages/cli/src/controller/codegen-controller.spec.ts @@ -3,21 +3,18 @@ import fs from 'fs'; import ejs from 'ejs'; -import {makeSchema, renderTemplate, generateSchema} from './codegen-controller'; +import {renderTemplate, generateSchema} from './codegen-controller'; jest.mock('fs', () => { const fsMock = jest.createMockFromModule('fs') as any; fsMock.promises = { writeFile: jest.fn(), access: jest.fn(), }; - fsMock.readFileSync = jest.fn(); return fsMock; }); jest.mock('ejs', () => { - const ejsMock = jest.createMockFromModule('ejs') as any; - ejsMock.renderFile = jest.fn(); - return ejsMock; + return jest.createMockFromModule('ejs') as any; }); const mockedTemplate = { @@ -28,39 +25,36 @@ const mockedTemplate = { }, }; -describe('Codegen can generate schema (mocked fs)', () => { - it('write schema to a empty project directory should fail', async () => { - (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.reject(new Error())); - await expect(makeSchema('classname', 'random data')).rejects.toThrow( - 'Write schema failed, not in project directory' - ); +describe('Codegen can generate schema (mocked)', () => { + it('generate schema should pass', async () => { + const schemaString = 'type goodEntity @entity {id: ID!}'; + (fs.readFileSync as jest.Mock).mockReturnValue(schemaString); + await expect(generateSchema()).resolves.not.toThrow(); }); - it('should throw error when write schema file failed', async () => { - (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); - (fs.promises.writeFile as jest.Mock).mockImplementation(async () => Promise.reject(new Error('write failed'))); - await expect(makeSchema('classname', 'random data')).rejects.toThrow(/write failed/); + it('generate schema should fail', async () => { + const schemaString = 'type badEntity @entity {id: Float!}'; + (fs.readFileSync as jest.Mock).mockReturnValue(schemaString); + await expect(generateSchema()).rejects.toThrow(); }); - it('write schema should pass', async () => { - (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); - (fs.promises.writeFile as jest.Mock).mockImplementation(async () => Promise.resolve()); - await expect(makeSchema('classname', 'random data')).resolves.not.toThrow(); + it('throw error when render ejs template in a folder missing models directory', async () => { + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.reject(new Error())); + await expect(renderTemplate('renderTemplateTest', mockedTemplate)).rejects.toThrow( + /Write schema failed, not in project directory/ + ); }); it('render ejs template with an incorrect format modelTemplate should throw', async () => { + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); (ejs.renderFile as jest.Mock).mockImplementation(async () => Promise.reject(new Error('render template failed'))); await expect(renderTemplate('renderTemplateTest', mockedTemplate)).rejects.toThrow(/render template failed/); }); - it('render ejs template with correct format modelTemplate should pass', async () => { + it('throw errors when write file failed in render template', async () => { + (fs.promises.access as jest.Mock).mockImplementation(async () => Promise.resolve()); (ejs.renderFile as jest.Mock).mockImplementation(async () => Promise.resolve()); - await expect(renderTemplate('renderTemplateTest', mockedTemplate)).resolves.not.toThrow(); - }); - - it('generate schema should pass', async () => { - const schemaString = 'type goodEntity @entity {id: ID!}'; - (fs.readFileSync as jest.Mock).mockReturnValue(schemaString); - await expect(generateSchema()).resolves.not.toThrow(); + (fs.promises.writeFile as jest.Mock).mockImplementation(async () => Promise.reject(new Error())); + await expect(renderTemplate('renderTemplateTest', mockedTemplate)).rejects.toThrow(); }); }); diff --git a/packages/cli/src/controller/codegen-controller.test.ts b/packages/cli/src/controller/codegen-controller.test.ts index 5db21bb395..2beb508943 100644 --- a/packages/cli/src/controller/codegen-controller.test.ts +++ b/packages/cli/src/controller/codegen-controller.test.ts @@ -1,20 +1,11 @@ // Copyright 2020-2021 OnFinality Limited authors & contributors // SPDX-License-Identifier: Apache-2.0 -import fs from 'fs'; -import os from 'os'; import path from 'path'; import {getAllEntities, buildSchema} from '@subql/common'; -import {processFields, makeSchema} from './codegen-controller'; +import {processFields} from './codegen-controller'; import {transformTypes} from './types-mapping'; -async function makeTempDir() { - const sep = path.sep; - const tmpDir = os.tmpdir(); - const tempPath = await fs.promises.mkdtemp(`${tmpDir}${sep}`); - return tempPath; -} - describe('Codegen can generate schema', () => { const badschema = buildSchema(path.join(__dirname, '../../test/badschema.graphql')); const badextractEntities = getAllEntities(badschema); @@ -48,12 +39,4 @@ describe('Codegen can generate schema', () => { //Float in badschema is not support, should throw error } }); - - it('save schema to a correct project directory should pass', async () => { - const testClassName = 'makeSchemaTest2'; - const tempPath = await makeTempDir(); - process.chdir(tempPath); - await fs.promises.mkdir('src/types/models', {recursive: true}); - await expect(makeSchema(testClassName, 'random text to add to schema')).resolves.not.toThrow(); - }); }); diff --git a/packages/cli/src/controller/codegen-controller.ts b/packages/cli/src/controller/codegen-controller.ts index 29edbf86aa..fdee3d3628 100644 --- a/packages/cli/src/controller/codegen-controller.ts +++ b/packages/cli/src/controller/codegen-controller.ts @@ -11,11 +11,12 @@ import {transformTypes} from './types-mapping'; const templatePath: string = path.resolve(__dirname, '../template/model.ts.ejs'); -// 4. Save the rendered schema -export async function makeSchema(className: string, data: string): Promise { - const typesPath = `${process.cwd()}/src/types/models`; +// 3. Render entity data in ejs template and write it +export async function renderTemplate(className: string, modelTemplate: ejs.Data): Promise { + const typesPath = path.resolve(`./src/types/models`); const filename = `${className}.ts`; const file = `${typesPath}/${filename}`; + let data: string; try { await fs.promises.access(typesPath); @@ -24,20 +25,17 @@ export async function makeSchema(className: string, data: string): Promise } try { - await fs.promises.writeFile(file, data); + data = await ejs.renderFile(templatePath, modelTemplate); } catch (err) { throw new Error(err.message); } - console.log(`>--- Schema ${className} generated !`); -} -// 3. Render entity data in ejs template -export async function renderTemplate(className: string, modelTemplate: ejs.Data): Promise { try { - const renderedFilePath = await ejs.renderFile(templatePath, modelTemplate); - await makeSchema(className, renderedFilePath); + await fs.promises.writeFile(file, data); } catch (err) { throw new Error(err.message); + } finally { + console.log(`---> Schema ${className} generated !`); } } diff --git a/packages/cli/src/controller/init-controller.spec.ts b/packages/cli/src/controller/init-controller.spec.ts index 5fdec7fe25..cf743b3239 100644 --- a/packages/cli/src/controller/init-controller.spec.ts +++ b/packages/cli/src/controller/init-controller.spec.ts @@ -25,8 +25,8 @@ async function makeTempDir() { describe('Cli can create project', () => { it('should resolves when starter project successful created', async () => { - const tempPath = makeTempDir(); - process.chdir(await tempPath); + const tempPath = await makeTempDir(); + process.chdir(tempPath); await createProject(projectName); await expect(fileExists(`./${projectName}`)).resolves.toEqual(true); });