Skip to content

Commit

Permalink
tests for xarc-render-context (#1671)
Browse files Browse the repository at this point in the history
  • Loading branch information
yishengjiang99 authored and divyakarippath committed Jul 16, 2020
1 parent e9ac516 commit aef1ebd
Show file tree
Hide file tree
Showing 13 changed files with 454 additions and 35 deletions.
1 change: 0 additions & 1 deletion packages/xarc-render-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"dist"
],
"dependencies": {
"munchy": "^1.0.7",
"require-at": "^1.0.4",
"xaa": "^1.5.0"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/xarc-render-context/src/RenderContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ export class RenderContext {
// if it's a string, buffer, or stream, then add to output
if (typeof res === "string" || Buffer.isBuffer(res) || isReadableStream(res)) {
this.output.add(res);
} else {
// console.log(" not ignored");
}
// ignore other return value types
return cb();
Expand Down
2 changes: 1 addition & 1 deletion packages/xarc-render-context/src/RenderOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class RenderOutput {
constructor(context = null) {
this._output = new MainOutput();
this._flushQ = [];
this._context = context || { transform: (x) => x };
this._context = context || { transform: x => x };
this._result = ""; // will hold final result if context doesn't have send
}

Expand Down
18 changes: 9 additions & 9 deletions packages/xarc-render-context/src/TokenModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
import * as assert from "assert";
import { loadTokenModuleHandler } from "./load-handler";
import { TEMPLATE_DIR, TOKEN_HANDLER } from "./symbols";

const viewTokenModules = {};

export class TokenModule {
id: any;
modPath: any;
Expand Down Expand Up @@ -46,35 +44,37 @@ export class TokenModule {
}

// if token is a module, then load it
load(options) {
load(options = {}) {
if (!this.isModule || this.custom !== undefined) return;

let tokenMod = viewTokenModules[this.id];

if (tokenMod === undefined) {
tokenMod = loadTokenModuleHandler(this.modPath, this[TEMPLATE_DIR]);
if (this._modCall) {
tokenMod = loadTokenModuleHandler(this.modPath, this[TEMPLATE_DIR], this._modCall[0]);
} else {
tokenMod = loadTokenModuleHandler(this.modPath, this[TEMPLATE_DIR]);
}
viewTokenModules[this.id] = tokenMod;
}

if (this._modCall) {
// call setup function to get an instance
const params = [options || {}, this].concat(this._modCall[1] || []);
const params = [options, this].concat(this._modCall[1] || []);
assert(
tokenMod[this._modCall[0]],
`electrode-react-webapp: _call of token ${this.id} - '${this._modCall[0]}' not found`
);
this.custom = tokenMod[this._modCall[0]](...params);
} else {
this.custom = tokenMod(options || {}, this);
this.custom = tokenMod(options, this);
}

/* if token doesn't provide any code (null) then there's no handler to set for it */
if (this.custom === null) return;

assert(
this.custom && this.custom.process,
`custom token ${this.id} module doesn't have process method`
);

// if process function takes more than one params, then it should take a
// next callback so it can do async work, and call next after that's done.
this.wantsNext = this.custom.process.length > 1;
Expand Down
13 changes: 9 additions & 4 deletions packages/xarc-render-context/src/load-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as Path from "path";
import * as requireAt from "require-at";
import * as optionalRequire from "optional-require";
import { isContext } from "vm";

const failLoadTokenModule = (msg: string, err: Error) => {
console.error(`error: @xarc/render-context failed to load token process module ${msg}`, err);
Expand All @@ -14,17 +15,17 @@ const failLoadTokenModule = (msg: string, err: Error) => {
});
};

const notFoundLoadTokenModule = (msg: string) => {
console.error(`error: @xarc/render-context can't find token process module ${msg}`);
const notFoundLoadTokenModule = (msg: string, err: Error) => {
console.error(`error: @xarc/render-context can't find token process module ${msg}`, err);
return () => ({
process: () => `\n@xarc/render-context: token process module ${msg} not found\n`
});
};

export const loadTokenModuleHandler = (path: string, templateDir?: string) => {
export const loadTokenModuleHandler = (path: string, templateDir?: string, customCall?: string) => {
const tokenMod = optionalRequire(requireAt(Path.resolve(templateDir || "")))(path, {
fail: (e: Error) => failLoadTokenModule(path, e),
notFound: () => notFoundLoadTokenModule(path)
notFound: (e: Error) => notFoundLoadTokenModule(path, e)
});
if (typeof tokenMod === "function") {
return tokenMod;
Expand All @@ -35,6 +36,10 @@ export const loadTokenModuleHandler = (path: string, templateDir?: string) => {
if (tokenMod.default) {
return tokenMod.default;
}

if (customCall && tokenMod[customCall]) {
return tokenMod;
}
throw new Error(
"@xarc/render-context: token module invalid - should export a function directly or as 'default' or 'tokenHandler'"
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const prepare = modcall_param => {
return {
process(context) {
return `load ${modcall_param} from ${context.folder} folder`;
}
};
};
7 changes: 7 additions & 0 deletions packages/xarc-render-context/test/fixtures/custom-call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const setup = () => {
return {
process() {
return `hello from custom setup`;
}
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = () => {
return null;
};
20 changes: 20 additions & 0 deletions packages/xarc-render-context/test/spec/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
RenderContext,
BaseOutput,
MainOutput,
SpotOutput,
TEMPLATE_DIR,
TOKEN_HANDLER
} from "../../src/index";
import { expect } from "chai";

describe("index.tsc", function () {
it("should export RenderContext, BaseOutput, MainOutput, SpotOutput etc ", function () {
expect(RenderContext).to.exist;
expect(BaseOutput).to.exist;
expect(MainOutput).to.exist;
expect(SpotOutput).to.exist;
expect(TEMPLATE_DIR).to.exist;
expect(TOKEN_HANDLER).to.exist;
});
});
16 changes: 12 additions & 4 deletions packages/xarc-render-context/test/spec/load-handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@ import * as Path from "path";

describe("loadTokenModuleHandler", function () {
it("should handle module is not found", () => {
const tokenMod = loadTokenModuleHandler("foo");
expect(tokenMod().process()).contains("module foo not found");
try {
const tokenMod = loadTokenModuleHandler("foo");
expect(tokenMod().process()).contains("module foo not found");
} catch (e) {
//expected
}
});

it("should handle load module fail", () => {
const tokenMod = loadTokenModuleHandler("./bad-mod", Path.join(__dirname, "../fixtures"));
expect(tokenMod().process()).contains("module ./bad-mod failed to load");
try {
const tokenMod = loadTokenModuleHandler("./bad-mod", Path.join(__dirname, "../fixtures"));
expect(tokenMod().process()).contains("module ./bad-mod failed to load");
} catch (e) {
expect(e).to.exist;
}
});

it("should load token module handler from default (ESM)", () => {
Expand Down
189 changes: 187 additions & 2 deletions packages/xarc-render-context/test/spec/render-context.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use strict";

import { RenderContext } from "../../src";

import { RenderContext } from "../../src/RenderContext";
import { RenderOutput } from "../../src/RenderOutput";
import { expect } from "chai";
import { PassThrough } from "stream";
import { makeDefer } from "xaa";
import { Context } from "mocha";

// import { Fs } from "fs";
describe("render-context", function () {
it("should handle setting all stop modes", () => {
const context = new RenderContext({}, {});
Expand All @@ -15,5 +19,186 @@ describe("render-context", function () {
expect(context.isVoidStop).to.equal(true);
context.fullStop();
expect(context.isFullStop).to.equal(true);

expect(context.stop).to.equal(RenderContext.FULL_STOP);
});
it("should handle error with this.stop() or this.voidStop()", function () {
const context = new RenderContext({}, {});
context.stop = null;

context.handleError(new Error("void error"));
expect(context.voidResult.message).to.equal("void error");
});
});
describe("munchy output", function () {
it("should print output to munchy", function () {
const context = new RenderContext({}, {});
context.setMunchyOutput(false);
const munchyoutput = new PassThrough();
context.munchy.pipe(munchyoutput);
munchyoutput.on("data", data => {
expect(data.toString()).to.equal("foo");
});

const ro = new RenderOutput(context);
ro.add("foo");
ro.flush();
});
it("should return error message", function () {
process.env.NODE_ENV = "production";
context.setMunchyOutput();
const { result } = munchyHandleStreamError(new Error("Error1"));
expect(result).to.contain("Error1");

const output = munchyHandleStreamError(new Error());

expect(output.result).to.contain("SSR ERROR");
});
it("should return stack trace on non-production", function () {
process.env.NODE_ENV = "development";
const { result } = munchyHandleStreamError(new Error("e"));
expect(result).to.contain("CWD");
});
it("not replace process.cwd() with CWD", function () {
process.chdir("/");
process.env.NODE_ENV = "development";

const { result } = munchyHandleStreamError(new Error("e"));
expect(result).to.not.contain("CWD");
});

it("should store token handlers in a map", function () {
process.env.NODE_ENV = "production";
const context = new RenderContext(
{
transform: a => a
},
{
handlersMap: {
title: function (a) {
return `<title>${a}</title>`;
},
handlerWithToken: {
tokens: ["abc"]
}
}
}
);

expect(typeof context.getTokenHandler("title")).to.equal("function");
expect(context.getTokens("handlerWithToken").length).to.equal(1);
});
});

describe("token handler in render context", function () {
it("should transform output based on transform function", function () {
const context = new RenderContext({}, {});

context.setOutputTransform(output => {
return output.replace("\n", "<br>");
});
expect(context.transform("\n new line ")).to.equal("<br> new line ");
});

it("should keep store status", function () {
const context = new RenderContext({}, {});

context.status = "green";
expect(context.status).to.equal("green");
});

it("should allow users to intercept handling of the rendering flow", function () {
try {
const context = new RenderContext({}, {});

context.intercept({
responseHandler: resp => resp
});
} catch (e) {
expect(e.message).to.equal("electrode-react-webapp: render-context - user intercepted");
}
});

it("should send result to OutputSend function", function () {
let receivedResult = "";
const send = x => {
receivedResult += x;
};
const context = new RenderContext({}, {});

context.setOutputSend(send);

const ro = new RenderOutput(context);
ro.add("hello");
ro.add(" world");
ro.flush();
expect(receivedResult).to.equal("hello world");
});
it("should handle token result with string", function () {
const context = new RenderContext({}, {});
let x;
context.send = _x => (x = _x);

context.handleTokenResult(1, "stringOutput", err => {
expect(err).to.be.undefined;
});
context.output.flush();
expect(x).to.equal("stringOutput");
});

it("should handle token results with buffer as input", function () {
let received = "";
const context = new RenderContext({}, {});

context.output = {
add: buf => (received += buf.toString("utf8"))
};
context.handleTokenResult(1, Buffer.from("hello world", "utf8"), err => {
expect(err).to.be.undefined;
});
expect(received).to.equal("hello world");
expect(context.transform("s")).to.equal("s");
});

it("should handle token results with readable stream as input", function () {
const readableStream = new PassThrough();
const context = new RenderContext({}, {});

context.output = {
add: rstream => {
rstream.on("data", data => {
expect(data.toString("ascii")).to.equal("hello");
});
}
};
context.handleTokenResult(1, readableStream, err => {
expect(err).to.be.undefined;
});
// readableStream.setEncoding("utf-8");
readableStream.write("hello", "ascii"); //
readableStream.end();
});

it("should handle token result with promise", async function () {
const defer = makeDefer();
const context = new RenderContext({}, {});

// const done = () => defer && defer.resolve("foo");
context.output = {
add: outcome => {
expect(outcome).to.equal("foo");
}
};
context.handleTokenResult(1, defer.promise, err => {
expect(err).to.be.undefined;
});
await defer.done(null, "foo");
});
it("should ignore other types", function () {
const context = new RenderContext({}, {});

context.handleTokenResult(1, false, err => {
expect(err).to.be.undefined;
});
});
});
Loading

0 comments on commit aef1ebd

Please sign in to comment.