Test typegraphs
Typegraph is the SDK for Metatype, used to author and define applications.. Typegraphs can be easily tested using common test suites in your preferred programming language.
The following next lines describe how you can test your typegraph. For Typescript SDK, we will be using vitest and pytest for the Python SDK in this example.
To test typegraphs in the typescript SDK, you first need to add vitest as a dev dependency to your metatype project.
You can follow this link on how to bootstrap a metatype application.
To install vitest, you can execute the command below in your terminal based on the runtime you are using for the project.
npm install -D vitest
After you have installed vitest, your project is set up for some tests. Create a test tg.test.ts
in /tests
directory from the root project dir. vitest discovers tests by file names, so ensure that your test names follow the following format below.
**/*.test.ts
**/*.spec.ts
For this example, the template typegraph generated from the meta new
command is used, which is the one down below.
...
export const tg = typegraph("example", (g) => {
const pub = Policy.public();
const deno = new DenoRuntime();
const python = new PythonRuntime();
g.expose({
add: python
.fromLambda(
t.struct({ first: t.float(), second: t.float() }),
t.float(),
{ code: "lambda x: x['first'] + x['second']" },
)
.withPolicy(pub),
multiply: deno
.func(t.struct({ first: t.float(), second: t.float() }), t.float(), {
code: "({first, second}) => first * second",
})
.withPolicy(pub),
});
});
For the typegraph test file, you can write these simple test cases to check the validity of your typegraphs.
import { assert, assertType, expect, test } from "vitest";
import { BasicAuth, tgDeploy, DeployResult } from "@typegraph/sdk/tg_deploy";
test("checks if typegraph output is computed", async () => {
const tg_output = await tg;
assertType<TypegraphOutput>(tg_output);
});
test("test if typegraph name is correct", async () => {
const tg_output = await tg;
assert(tg_output.name === "example", "typegraph name is correct");
});
test("test if serialize function exists", async () => {
const tg_output = await tg;
assertType<Function>(typeof tg_output.serialize);
});
The above were simple tests you can execute against the output of the typegraph function. You can also do a serialization test to check if the typegraph is serialized successfully.
To run the tests in watch mode, you can use the following command.
vitest watch
...
let reusableTgOutput;
test("test if typegraph serialization works", async () => {
const tg_output = await tg;
const params = {
typegraphPath: "api/example.mjs",
prefix: "",
artifactResolution: true,
codegen: false,
prismaMigration: {
migrationsDir: "prisma-migrations",
migrationActions: Object.entries({}),
defaultMigrationAction: {
apply: true,
create: false,
reset: false,
},
},
pretty: false,
};
const serialized = tg_output.serialize(params);
// cache the serialize result as the serialize function can only be called one time
reusableTgOutput = {
...tg_output,
serialize: (params) => serialized,
};
assert(serialized !== null, "Serialization Successful");
assertType<TgFinalizationResult>(serialized);
});
Furthermore, you can test typegraph deployment and running a query against a typegate instance. You first test for typegraph deploy, then querying into a typegate instance. The following tests depict on how you can do that.
Make sure you have a typegate node running for the next tests to work.
...
const gate = "http://localhost:7891";
const typegraph_name = "example";
test("test typegraph deploy to typegate", async () => {
const auth = new BasicAuth("admin", "password");
const deploy_result = await tgDeploy(reusableTgOutput, {
typegate: {
url: gate,
auth: auth
},
typegraphPath: "api/example.mjs",
prefix: "",
secrets: {},
migrationsDir: "prisma-migrations",
migrationActions: {},
defaultMigrationAction: {
apply: false,
create: false,
reset: false
}
});
assertType<DeployResult>(deploy_result);
assert(deploy_result.serialized !== null);
expect(deploy_result.response).toMatchObject({
name: "example",
messages: [],
migrations: [],
});
});
test("test defined endpoints from the typegraph", async () => {
const query = `
{
add(first: 17, second: 20)
}
`;
const url = `${gate}/${typegraph_name}`;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({query})
});
assert(response.ok);
expect(response.status).toBe(200);
const responseBody = await response.json();
const expectedResult = {data: {add: 37}};
assert.exists(responseBody);
expect(responseBody).toMatchObject(expectedResult)
});
test("test typegraph undeployment", async () => {
const undeploy_result = await tgRemove(
"example",
{
typegate: {
auth: new BasicAuth("admin", "password"),
url: gate
}
}
);
expect(undeploy_result.typegate).toMatchObject(
{ data: { removeTypegraphs: true } }
);
});
It's recommended to setup an after and before test hooks to clean up any database changes. So make sure to include those keep the state before and after tests the same.
You don't have to stop here, you can test various outputs you get from running the typegraph function and querying directly into the deployed typegraphs. You can add more test cases to make your app robust.