1

Using tape, how can I write a custom assertion method to use in place of t.equal()? Or is there a test assertion method that can check for a substring so that the entire string I'm testing does not have to be compared verbatim using t.deepEqual()?

var test = require("tape")

test('messages contain key words', function (t) {
  // this is what I'm using:
  t.equal(MyEncode(Fruit).indexOf('eat more') > -1,true,'should contain "eat more"')

  // this is what I want:
  t.contains(myEncode(Fruit),'eat more','should contain "eat more"')
  t.end()
})

When I test myEncode, I can see that the string does not contain the substring, but I cannot view the actual value because it evaluates only as false, which is not informative:

  not ok 1 should contain "eat more"
---
  operator: equal
  expected: true
  actual:   false
  at: checkCmd (/test.js:63:11)
...

From reading the test output above, I don't know if my test was too restrictive, or the output was actually incorrect. Instead, I would like to see the actual value returned by myEncode to speed locating the problem:

  not ok 2 should contain "eat more"
---
  operator: contains
  expected: "eat more"
  actual:   "Apples are allowed to be eaten on weekdays and weekends"
  at: checkCmd (/test.js:66:11)
...
  • I installed [extend-tape](https://www.npmjs.com/package/extend-tape), but it turns out that it requires the `import` function, which is not supported yet by V8, so `import tape from 'tape'; import addAssertions from 'extend-tape';` did not work. – user6641586 Jul 27 '16 at 23:13

1 Answers1

2

I got it to work, thanks to @mbostock example test method in the github tape issue How to define new test methods? #154.

Function to be tested, typically in another file (e.g. appToTest.js)

function brownFox(argument) {
    return "The "+argument+" fox jumped"
} 
exports.brownFox = brownFox

The test script:

// Test module typically named test.js
var test = require("tape")

var f = require("./appToTest")
// regular built-in test

test('String must match exactly', function (t) { // can be too specific
    t.deepEqual(f.brownFox('quick brown'), "The quick brown fox jumped") // should pass
    t.deepEqual(f.brownFox('quick black'), "The quick brown fox jumped") // will fail
    t.deepEqual(f.brownFox('quick white'), "The quick white fox jumped") // should pass
    t.comment('Strings must be fully specified to match word for word')
    t.end()
})
// It can be too tedious to maintain the test string to always 
// match exactly the string in the code being tested

// I don't care what the fox is as long as it jumped
// Since there is no "contains" test in tape, I hack t.equal()
test('String should contain a fox', function (t) {
    // does not show actual value when test fails; shows true or false instead
    // "jumped" must be tediously repeated to know what the test is about
    t.equal(f.brownFox('quick brown').indexOf("jumped") > -1, true, "contains jumped") // should pass
    t.equal(f.brownFox('quick black').indexOf("junped") > -1, true, "contains jumped") // should fail
    t.comment('failures are not descriptive')
    t.end()
})
// Using equal() can result in more time spent fixing or adjusting the test
// than coding the application

// So define your own tape test method
/////////////// Example of defining a custom tape test method
test.Test.prototype.stringContains = function(actual, contents, message) {
  this._assert(actual.indexOf(contents) > -1, {
    message: message || 'should contain '+contents,
    operator: 'stringContains',
    actual: actual,
    expected: contents
  });
};

/////////////// Example using a custom tape test method
test('String should contain a fox', function (t) {
    // shows actual value when test fails
    t.stringContains(f.brownFox('quick brown'), "jumped") // should pass
    t.stringContains(f.brownFox('quick brown'), "junped") // should fail
    // still supports custom message to override default message:
    t.stringContains(f.brownFox('quick brown'), "jumped", 'must contain "jumped"') // should pass
    t.stringContains(f.brownFox('quik white'), "jumped") // should pass
    t.comment('failures are more descriptive')
    t.end()
})

Note that the customized test output now reports the "actual" string:

TAP version 13
# String must match exactly
ok 1 should be equivalent
not ok 2 should be equivalent
  ---
    operator: deepEqual
    expected: 'The quick brown fox jumped'
    actual:   'The quick black fox jumped'
    at: Test.<anonymous> (./tape-test.js:9:7)
  ...
ok 3 should be equivalent
# Strings must be fully specified to match word for word
# String should contain a fox
ok 4 contains jumped
not ok 5 contains jumped
  ---
    operator: equal
    expected: true
    actual:   false
    at: Test.<anonymous> (./tape-test.js:23:7)
  ...
# failures are not descriptive
# String should contain a fox
ok 6 should contain jumped
not ok 7 should contain junped
  ---
    operator: stringContains
    expected: 'junped'
    actual:   'The quick brown fox jumped'
    at: Test.test.Test.stringContains (./tape-test.js:33:8)
ok 8 must contain "jumped"
ok 9 should contain jumped
# failures are more descriptive

1..9
# tests 9
# pass  6
# fail  3

I installed extend-tape, and then realized I would have to use it with babel because V8 does not support import yet, but I did not want to add babel as a dependency.

Since the code above works, I don't see the point of using extend-tape.