UNPKG

passbook

Version:
256 lines (219 loc) 7.84 kB
var assert = require("assert"); var createTemplate = require("../"); var Crypto = require("crypto"); var execFile = require("child_process").execFile; var File = require("fs"); describe("Pass", function() { before(function() { this.template = createTemplate("coupon", { passTypeIdentifier: "pass.com.example.passbook", teamIdentifier: "MXL" }); this.template.keys(__dirname + "/../keys", "secret"); this.fields = { serialNumber: "123456", organizationName: "Acme flowers", description: "20% of black roses" }; }); describe("from template", function() { before(function() { this.pass = this.template.createPass(); }); it("should copy template fields", function() { assert.equal(this.pass.fields.passTypeIdentifier, "pass.com.example.passbook"); }); it("should start with no images", function() { assert.deepEqual(this.pass.images, {}); }); it("should create a structure based on style", function() { assert(this.pass.fields.coupon); assert(!this.pass.fields.eventTicket); }); }); describe("without serial number", function() { it("should not be valid", function() { var pass = this.template.createPass(cloneExcept(this.fields, "serialNumber")); try { pass.validate(); assert(false, "Pass validated without serialNumber"); } catch(ex) { assert.equal(ex.message, "Missing field serialNumber"); } }); }); describe("without organization name", function() { it("should not be valid", function() { var pass = this.template.createPass(cloneExcept(this.fields, "organizationName")); try { pass.validate(); assert(false, "Pass validated without organizationName"); } catch(ex) { assert.equal(ex.message, "Missing field organizationName"); } }); }); describe("without description", function() { it("should not be valid", function() { var pass = this.template.createPass(cloneExcept(this.fields, "description")); try { pass.validate(); assert(false, "Pass validated without description"); } catch(ex) { assert.equal(ex.message, "Missing field description"); } }); }); describe("without icon.png", function() { it("should not be valid", function() { var pass = this.template.createPass(this.fields); try { pass.validate(); assert(false, "Pass validated without icon.png"); } catch(ex) { assert.equal(ex.message, "Missing image icon.png"); } }); }); describe("without logo.png", function() { var validationError; before(function(done) { var pass = this.template.createPass(this.fields); pass.icon("icon.png"); var file = File.createWriteStream("/tmp/pass.pkpass"); pass.pipe(file); pass.on("done", done); pass.on("error", function(error) { validationError = error; done(); }); }); it("should not be valid", function() { assert(validationError, "Pass validated without logo.png"); assert.equal(validationError.message, "Missing image logo.png"); }); }); describe("with companion app keys", function() { before(function() { var fields = cloneExcept(this.fields, "not_used"); fields.appLaunchURL = "some_app_launch_url"; fields.associatedStoreIdentifiers = [123, 456]; this.pass = this.template.createPass(fields); }); it("includes the app launch URL", function() { assert.equal(this.pass.fields.appLaunchURL, "some_app_launch_url"); }); it("includes the associated store identifiers", function() { assert.deepEqual(this.pass.fields.associatedStoreIdentifiers, [123, 456]); }); }); describe("generated", function() { before(function() { this.pass = this.template.createPass(this.fields); this.pass.loadImagesFrom(__dirname + "/resources"); this.pass.headerFields.add("date", "Date", "Nov 1"); this.pass.primaryFields.add([ { key: "location", label: "Place", value: "High ground" } ]); }); before(function(done) { if (File.existsSync("/tmp/pass.pkpass")) File.unlinkSync("/tmp/pass.pkpass"); var file = File.createWriteStream("/tmp/pass.pkpass"); this.pass.pipe(file); this.pass.on("end", done); }); it("should be a valid ZIP", function(done) { execFile("unzip", ["-t", "/tmp/pass.pkpass"], function(error, stdout) { if (error) error = new Error(stdout); done(error); }); }); it("should contain pass.json", function(done) { unzip("/tmp/pass.pkpass", "pass.json", function(error, buffer) { assert.deepEqual(JSON.parse(buffer), { passTypeIdentifier: 'pass.com.example.passbook', teamIdentifier: 'MXL', serialNumber: '123456', organizationName: 'Acme flowers', description: '20% of black roses', coupon: { headerFields: [ { key: "date", label: "Date", value: "Nov 1" } ], primaryFields: [ { key: "location", label: "Place", value: "High ground" } ] }, formatVersion: 1 }); done(); }); }); it("should contain a manifest", function(done) { unzip("/tmp/pass.pkpass", "manifest.json", function(error, buffer) { assert.deepEqual(JSON.parse(buffer), { "pass.json": "87c2bd96d4bcaf55f0d4d7846a5ae1fea85ea628", "icon.png": "e0f0bcd503f6117bce6a1a3ff8a68e36d26ae47f", "icon@2x.png": "10e4a72dbb02cc526cef967420553b459ccf2b9e", "logo.png": "abc97e3b2bc3b0e412ca4a853ba5fd90fe063551", "logo@2x.png": "87ca39ddc347646b5625062a349de4d3f06714ac", "strip.png": "68fc532d6c76e7c6c0dbb9b45165e62fbb8e9e32", "strip@2x.png": "17e4f5598362d21f92aa75bc66e2011a2310f48e", "thumbnail.png": "e199fc0e2839ad5698b206d5f4b7d8cb2418927c", "thumbnail@2x.png": "ac640c623741c0081fb1592d6353ebb03122244f" }); done(); }); }); it("should contain a signature", function(done) { execFile("signpass", ["-v", "/tmp/pass.pkpass"], function(error, stdout) { assert(/\*\*\* SUCCEEDED \*\*\*/.test(stdout), stdout); done(); }); }); it("should contain the icon", function(done) { unzip("/tmp/pass.pkpass", "icon.png", function(error, buffer) { assert.equal(Crypto.createHash("sha1").update(buffer).digest("hex"), "e0f0bcd503f6117bce6a1a3ff8a68e36d26ae47f"); done(); }); }); it("should contain the logo", function(done) { unzip("/tmp/pass.pkpass", "logo.png", function(error, buffer) { assert.equal(Crypto.createHash("sha1").update(buffer).digest("hex"), "abc97e3b2bc3b0e412ca4a853ba5fd90fe063551"); done(); }); }); }); }); // Clone all the fields in object, except the named field, and return a new // object. // // object - Object to clone // field - Except this field function cloneExcept(object, field) { var clone = {}; for (var key in object) { if (key !== field) clone[key] = object[key]; } return clone; } function unzip(zipFile, filename, callback) { execFile("unzip", ["-p", zipFile, filename], { encoding: "binary" }, function(error, stdout) { if (error) { callback(new Error(stdout)); } else { callback(null, Buffer.from(stdout, "binary")); } }); }