Skip to content

Commit a6101dd

Browse files
committed
Add unit tests.
1 parent 35f8392 commit a6101dd

File tree

2 files changed

+267
-2
lines changed

2 files changed

+267
-2
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
import * as chai from "chai";
2+
import * as clc from "colorette";
3+
import * as fs from "fs-extra";
4+
import * as yaml from "js-yaml";
5+
import * as sinon from "sinon";
6+
7+
import { addSchemaToDataConnectYaml, askQuestions, actuate, SchemaRequiredInfo } from "./schema";
8+
import { Setup } from "../..";
9+
import { Config } from "../../../config";
10+
import * as load from "../../../dataconnect/load";
11+
import { DataConnectYaml, ServiceInfo } from "../../../dataconnect/types";
12+
import * as experiments from "../../../experiments";
13+
import * as prompt from "../../../prompt";
14+
15+
const expect = chai.expect;
16+
17+
describe("addSchemaToDataConnectYaml", () => {
18+
let schemaRequiredInfo: SchemaRequiredInfo;
19+
let dataConnectYaml: DataConnectYaml;
20+
21+
beforeEach(() => {
22+
dataConnectYaml = {
23+
location: "us-central1",
24+
serviceId: "test-service",
25+
connectorDirs: [],
26+
};
27+
schemaRequiredInfo = {
28+
id: "test_resolver",
29+
uri: "www.test.com",
30+
serviceInfo: {} as ServiceInfo,
31+
};
32+
});
33+
34+
it("add schema to dataconnect.yaml with `schema` field", () => {
35+
dataConnectYaml.schema = {
36+
source: "./schema",
37+
datasource: {},
38+
};
39+
addSchemaToDataConnectYaml(dataConnectYaml, schemaRequiredInfo);
40+
expect(dataConnectYaml.schema).to.be.undefined;
41+
expect(dataConnectYaml.schemas).to.have.lengthOf(2);
42+
expect(dataConnectYaml.schemas).to.deep.equal([
43+
{
44+
source: "./schema",
45+
datasource: {},
46+
},
47+
{
48+
source: "./schema_test_resolver",
49+
id: "test_resolver",
50+
datasource: {
51+
httpGraphql: {
52+
uri: "www.test.com",
53+
},
54+
},
55+
},
56+
]);
57+
});
58+
it("add schema to dataconnect.yaml with `schemas` field", () => {
59+
dataConnectYaml.schemas = [
60+
{
61+
source: "./schema",
62+
datasource: {},
63+
},
64+
{
65+
source: "./schema_existing",
66+
datasource: {},
67+
},
68+
];
69+
addSchemaToDataConnectYaml(dataConnectYaml, schemaRequiredInfo);
70+
expect(dataConnectYaml.schema).to.be.undefined;
71+
expect(dataConnectYaml.schemas).to.have.lengthOf(2);
72+
expect(dataConnectYaml.schemas).to.deep.equal([
73+
{
74+
source: "./schema",
75+
datasource: {},
76+
},
77+
{
78+
source: "./schema_existing",
79+
datasource: {},
80+
},
81+
{
82+
source: "./schema_test_resolver",
83+
id: "test_resolver",
84+
datasource: {
85+
httpGraphql: {
86+
uri: "www.test.com",
87+
},
88+
},
89+
},
90+
]);
91+
});
92+
});
93+
94+
describe("askQuestions", () => {
95+
let setup: Setup;
96+
let config: Config;
97+
let experimentsStub: sinon.SinonStub;
98+
let loadAllStub: sinon.SinonStub;
99+
let selectStub: sinon.SinonStub;
100+
let inputStub: sinon.SinonStub;
101+
102+
beforeEach(() => {
103+
setup = {
104+
config: {} as any,
105+
rcfile: {} as any,
106+
instructions: [],
107+
};
108+
config = new Config({}, { projectDir: "." });
109+
experimentsStub = sinon.stub(experiments, "isEnabled");
110+
loadAllStub = sinon.stub(load, "loadAll");
111+
selectStub = sinon.stub(prompt, "select");
112+
inputStub = sinon.stub(prompt, "input");
113+
});
114+
115+
afterEach(() => {
116+
sinon.restore();
117+
});
118+
119+
it("should throw error when fdcwebhooks experiment is not enabled", async () => {
120+
experimentsStub.resolves(false);
121+
122+
try {
123+
await askQuestions(setup, config);
124+
} catch (err: any) {
125+
expect(err.message).to.equal("Unsupported command.");
126+
}
127+
});
128+
129+
it("should throw error when no services", async () => {
130+
experimentsStub.resolves(true);
131+
loadAllStub.resolves([]);
132+
133+
try {
134+
await askQuestions(setup, config);
135+
} catch (err: any) {
136+
expect(err.message).to.equal(
137+
`No Firebase Data Connect workspace found. Run ${clc.bold(
138+
"firebase init dataconnect",
139+
)} to set up a service and main schema.`,
140+
);
141+
}
142+
});
143+
144+
it("should skip service selection when exactly one service", async () => {
145+
experimentsStub.resolves(true);
146+
loadAllStub.resolves([{ serviceName: "service-name" }]);
147+
inputStub.onFirstCall().resolves("test_resolver");
148+
inputStub.onSecondCall().resolves("www.test.com");
149+
150+
await askQuestions(setup, config);
151+
152+
expect(selectStub.called).to.be.false;
153+
expect(inputStub.calledTwice).to.be.true;
154+
expect(setup.featureInfo?.dataconnectSchema?.id).to.equal("test_resolver");
155+
expect(setup.featureInfo?.dataconnectSchema?.uri).to.equal("www.test.com");
156+
expect(setup.featureInfo?.dataconnectSchema?.serviceInfo.serviceName).to.equal("service-name");
157+
});
158+
159+
it("should prompt for service selection when multiple services", async () => {
160+
experimentsStub.resolves(true);
161+
loadAllStub.resolves([
162+
{ serviceName: "service-name" },
163+
{ serviceName: "another-service-name" },
164+
]);
165+
selectStub.resolves({ serviceName: "another-service-name" });
166+
inputStub.onFirstCall().resolves("test_resolver");
167+
inputStub.onSecondCall().resolves("www.test.com");
168+
169+
await askQuestions(setup, config);
170+
171+
expect(selectStub.calledOnce).to.be.true;
172+
expect(inputStub.calledTwice).to.be.true;
173+
expect(setup.featureInfo?.dataconnectSchema?.id).to.equal("test_resolver");
174+
expect(setup.featureInfo?.dataconnectSchema?.uri).to.equal("www.test.com");
175+
expect(setup.featureInfo?.dataconnectSchema?.serviceInfo.serviceName).to.equal(
176+
"another-service-name",
177+
);
178+
});
179+
});
180+
181+
describe("actuate", () => {
182+
let setup: Setup;
183+
let config: Config;
184+
let experimentsStub: sinon.SinonStub;
185+
let writeProjectFileStub: sinon.SinonStub;
186+
let ensureSyncStub: sinon.SinonStub;
187+
188+
beforeEach(() => {
189+
experimentsStub = sinon.stub(experiments, "isEnabled");
190+
writeProjectFileStub = sinon.stub();
191+
ensureSyncStub = sinon.stub(fs, "ensureFileSync");
192+
193+
setup = {
194+
config: { projectDir: "/path/to/project" } as any,
195+
rcfile: {} as any,
196+
featureInfo: {
197+
dataconnectSchema: {
198+
id: "test_resolver",
199+
uri: "www.test.com",
200+
serviceInfo: {
201+
sourceDirectory: "/path/to/service",
202+
serviceName: "test-service",
203+
schemas: [],
204+
dataConnectYaml: {
205+
location: "us-central1",
206+
serviceId: "test-service",
207+
schemas: [
208+
{
209+
source: "./schema",
210+
datasource: {},
211+
},
212+
],
213+
connectorDirs: [],
214+
},
215+
connectorInfo: [],
216+
},
217+
},
218+
},
219+
instructions: [],
220+
};
221+
config = {
222+
writeProjectFile: writeProjectFileStub,
223+
projectDir: "/path/to/project",
224+
get: () => ({}),
225+
set: () => ({}),
226+
has: () => true,
227+
path: (p: string) => p,
228+
readProjectFile: () => ({}),
229+
projectFileExists: () => true,
230+
deleteProjectFile: () => ({}),
231+
confirmWriteProjectFile: async () => true,
232+
askWriteProjectFile: async () => ({}),
233+
} as unknown as Config;
234+
});
235+
236+
afterEach(() => {
237+
sinon.restore();
238+
});
239+
240+
it("should no-op when fdcwebhooks experiment is not enabled", async () => {
241+
experimentsStub.resolves(false);
242+
243+
await actuate(setup, config);
244+
245+
expect(writeProjectFileStub.called).to.be.false;
246+
expect(ensureSyncStub.called).to.be.false;
247+
});
248+
249+
it("should write dataconnect.yaml and set up empty secondary schema file", async () => {
250+
experimentsStub.resolves(true);
251+
252+
await actuate(setup, config);
253+
254+
expect(writeProjectFileStub.calledOnce).to.be.true;
255+
const writtenYamlPath = writeProjectFileStub.getCall(0).args[0];
256+
const writtenYamlContents = writeProjectFileStub.getCall(0).args[1];
257+
const parsedYaml = yaml.load(writtenYamlContents);
258+
expect(writtenYamlPath).to.equal("/path/to/service/dataconnect.yaml");
259+
expect(parsedYaml.schemas).to.have.lengthOf(2);
260+
expect(ensureSyncStub.calledOnce).to.be.true;
261+
const writtenSchemaPath = ensureSyncStub.getCall(0).args[0];
262+
expect(writtenSchemaPath).to.equal("/path/to/service/schema_test_resolver/schema.gql");
263+
});
264+
});

src/init/features/dataconnect/schema.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export async function actuate(setup: Setup, config: Config) {
8181
try {
8282
actuateWithInfo(config, schemaInfo);
8383
} finally {
84-
const source: Source = setup.featureInfo?.dataconnectSource || "init_schema";
84+
const source: Source = "init_schema";
8585
void trackGA4(
8686
"dataconnect_init",
8787
{
@@ -115,7 +115,8 @@ function actuateWithInfo(config: Config, info: SchemaRequiredInfo) {
115115
fs.ensureFileSync(join(info.serviceInfo.sourceDirectory, `schema_${info.id}`, "schema.gql"));
116116
}
117117

118-
function addSchemaToDataConnectYaml(
118+
/** Add secondary schema configuration to dataconnect.yaml in place */
119+
export function addSchemaToDataConnectYaml(
119120
dataConnectYaml: DataConnectYaml,
120121
info: SchemaRequiredInfo,
121122
): void {

0 commit comments

Comments
 (0)