Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions src/deploy/firestore/deploy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { expect } from "chai";
import * as sinon from "sinon";
import deploy from "./deploy";
import { RulesDeploy, RulesetServiceType } from "../../rulesDeploy";
import { FirestoreApi } from "../../firestore/api";
import * as utils from "../../utils";
import { Options } from "../../options";

describe("firestore deploy", () => {
let createRulesetsStub: sinon.SinonStub;
let deployIndexesStub: sinon.SinonStub;
let sleepStub: sinon.SinonStub;

beforeEach(() => {
createRulesetsStub = sinon.stub(RulesDeploy.prototype, "createRulesets").resolves();
deployIndexesStub = sinon.stub(FirestoreApi.prototype, "deploy").resolves();
sleepStub = sinon.stub(utils, "sleep").resolves();
});

afterEach(() => {
sinon.restore();
});

it("should skip if no rules or indexes in context", async () => {
const context = {};
await deploy(context, {} as unknown as Options);
expect(createRulesetsStub).to.not.have.been.called;
expect(deployIndexesStub).to.not.have.been.called;
});

it("should deploy rules if context.firestoreRules is present", async () => {
const context = {
firestoreRules: true,
firestore: {
rulesDeploy: new RulesDeploy({} as unknown as Options, {} as unknown as RulesetServiceType),
},
};

await deploy(context, {} as unknown as Options);

expect(createRulesetsStub).to.have.been.calledWith(RulesetServiceType.CLOUD_FIRESTORE);
});

it("should skip rules if rulesDeploy is missing", async () => {
const context = {
firestoreRules: true,
};

await deploy(context, {} as unknown as Options);

expect(createRulesetsStub).to.not.have.been.called;
});

it("should deploy indexes if context.firestoreIndexes is present", async () => {
const context = {
firestoreIndexes: true,
firestore: {
indexes: [
{
databaseId: "(default)",
indexesFileName: "firestore.indexes.json",
indexesRawSpec: {
indexes: [{ collectionGroup: "users", queryScope: "COLLECTION", fields: [] }],
},
},
],
},
};

await deploy(context, {} as unknown as Options);

expect(deployIndexesStub).to.have.been.calledOnce;
});

it("should retry index deployment on 404 error", async () => {
const context = {
firestoreIndexes: true,
firestore: {
indexes: [
{
databaseId: "(default)",
indexesFileName: "firestore.indexes.json",
indexesRawSpec: {
indexes: [{ collectionGroup: "users", queryScope: "COLLECTION", fields: [] }],
},
},
],
},
};

const notFoundError = new Error("Not found") as unknown as { status: number };
notFoundError.status = 404;

deployIndexesStub.onFirstCall().rejects(notFoundError);
deployIndexesStub.onSecondCall().resolves();

await deploy(context, {} as unknown as Options);

expect(deployIndexesStub).to.have.been.calledTwice;
expect(sleepStub).to.have.been.calledOnce;
});

it("should bubble up non-404 errors during index deployment", async () => {
const context = {
firestoreIndexes: true,
firestore: {
indexes: [
{
databaseId: "(default)",
indexesFileName: "firestore.indexes.json",
indexesRawSpec: {
indexes: [{ collectionGroup: "users", queryScope: "COLLECTION", fields: [] }],
},
},
],
},
};

const genericError = new Error("Permission denied") as unknown as { status: number };
genericError.status = 403;

deployIndexesStub.rejects(genericError);

await expect(deploy(context, {} as unknown as Options)).to.be.rejectedWith("Permission denied");
});
});
Loading