Skip to content

Instantly share code, notes, and snippets.

View goldbergyoni's full-sized avatar
💭
I may be slow to respond

Yoni Goldberg goldbergyoni

💭
I may be slow to respond
View GitHub Profile
@goldbergyoni
goldbergyoni / cloudSettings
Last active September 23, 2018 09:34
Visual Studio Code Settings Sync Gist
{"lastUpload":"2018-09-23T09:34:34.812Z","extensionVersion":"v3.1.2"}
@goldbergyoni
goldbergyoni / app.js
Created July 4, 2018 09:02
Realtime event emitters
const EventEmitter = require("events");
class Session extends EventEmitter {
constructor(id) {
super();
this.id = id;
}
start() {
console.log(`Session is about to start ${this.id}`);
@goldbergyoni
goldbergyoni / testing-the-internal.js
Created December 20, 2018 23:43
Testing whitebox
class ProductService{
//this method is only used internally
//Change this name will make the tests fail
calculateVAT(priceWithoutVAT){
return {finalPrice: priceWithoutVAT * 1.2};
//Change the result format or key name above will make the tests fail
}
//public method
getPrice(productId){
const desiredProduct= DB.getProduct(productId);
@goldbergyoni
goldbergyoni / testing-lint-errors.js
Last active December 23, 2018 11:02
Typical test linting findings
describe("Too short description", () => {
const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead
it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words
});
it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite
expect("somevalue"); // error:no-assert
});
it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests
@goldbergyoni
goldbergyoni / indirect-test.js
Created December 23, 2018 19:08
A test with many helpers and level of indirection
test("When getting orders report, get the existing orders", () => {
const queryObject = QueryHelpers.getQueryObject(config.DBInstanceURL);
const reportConfiguration = ReportHelpers.getReportConfig();//What report config did we get? have to leave the test and read
userHelpers.prepareQueryPermissions(reportConfiguration);//what this one is doing? have to leave the test and read
const result = queryObject.query(reportConfiguration);
assertThatReportIsValid();//I wonder what this one does, have to leave the test and read
expect(result).to.be.an('array').that.does.include({id:1, productd:2, orderStatus:"approved"});
//how do we know this order exist? have to leave the test and check
})
@goldbergyoni
goldbergyoni / explicit-test.js
Created December 23, 2018 19:10
A test that one can read without leaving and visiting external code
it("When getting orders report, get the existing orders", () => {
//This one hopefully is telling a direct and explicit story
const orderWeJustAdded = ordersTestHelpers.addRandomNewOrder();
const queryObject = newQueryObject(config.DBInstanceURL, queryOptions.deep, useCache:false);
const result = queryObject.query(config.adminUserToken, reports.orders, pageSize:200);
expect(result).to.be.an('array').that.does.include(orderWeJustAdded);
})
@goldbergyoni
goldbergyoni / false-coverage.js
Last active December 24, 2018 19:43
A test triggers high coverage with no assertions
function addNewOrder(newOrder) {
logger.log(`Adding new order ${newOrder}`);
DB.save(newOrder);
Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`);
return {approved: true};
}
it("Test addNewOrder, don't use such test names", () => {
addNewOrder({asignee: "John@mailer.com",price: 120});
@goldbergyoni
goldbergyoni / 3parts.js
Created December 26, 2018 13:55
Test name constitutes 3 parts
//1. unit under test
describe('Products Service', function() {
describe('Add new product', function() {
//2. scenario and 3. expectation
it('When no price is specified, then the product status is pending approval', ()=> {
const newProduct = new ProductService().add(...);
expect(newProduct.status).to.equal('pendingApproval');
});
});
});
@goldbergyoni
goldbergyoni / mocksarebad.js
Created December 26, 2018 14:02
Mocks focus on the internal
it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => {
//Assume we already added a product
const dataAccessMock = sinon.mock(DAL);
//hmmm BAD: testing the internals is actually our main goal here, not just a side-effecr
dataAccessMock.expects("deleteProduct").once().withArgs(DBConfig, theProductWeJustAdded, true, false);
new ProductService().deletePrice(theProductWeJustAdded);
mock.verify();
});
@goldbergyoni
goldbergyoni / spies.js
Created December 26, 2018 14:07
Spies
it("When a valid product is about to be deleted, ensure an email is sent", async () => {
//Assume we already added here a product
const spy = sinon.spy(Emailer.prototype, "sendEmail");
new ProductService().deletePrice(theProductWeJustAdded);
//hmmm OK: we deal with internals? Yes, but as a side effect of testing the requirements (sending an email)
});