This page lists some notes and examples about the prototype, and the concept as such.

The initial concept is at w:no:User:Jeblad/Module:BDD, with backup at keybase and is now reimplemented as Github:jeblad/Pickle. (Keybase launches encrypted git)

Import of module under test

At present the module under test is imported by require(). This is not a good solution, it is like using a global var for the module. Instead, the modules should be injected into the tests. This imply that the test callbacks are held in an unevaluated state until the tested module is injected.

Present call is like this at the top of the pickle page Module:Foo (This is according to w:no:User:Jeblad/Module:BDD/dok)

require 'Module:Bar'()

Future form will be like this

require 'Module:Foo'('Module:Bar')

or a call from the console for Module:Foo that is the pickle page


or a call from the console for Module:Bar that is the tested module

=require 'Module:Bar'(p)

or from wikitext


or from the special test runner


The last form will find all subpages called Module:Bar/anything.pickle and link them, giving the user the option to navigate to them and possibly run them. (TODO:Is this still supported?)

If the __call() is without arguments then the base page will be found and used, if possible. That is a pickle page named as Module:Bar/Foo will work, while a pickle page that is itself a base page will not work.

Regression testing

In the code for proof of concept require() was used to load the module under test, and because of that there was regression testing in place. If the code is changed to use dependency injection the reevaluation after changes must be done in some other way, possibly by the {{#pickle}} parser function.

Interactive runs

  • There will be a button below the console on the pickle page that runs this pickle with the base page as injection.
  • There will be a button below the console on the page for the tested module, that runs all found pickles with the tested module as injection.
  • There will be a button on the doc part of the pickle page to rerun the tests (Not sure if it is necessary)

Conditional require

The __call() metamethod will check if it is run from the page that is required, and if so pick up either an array or a function to construct the array instead of loading the required module.


Check whether luassert library should be used instead of the expectations. The later is better on reporting whats going on, but the former is in common use.

Looping over testdata

Testdata can be provided for all of describe, context and it, but only makes sense for context and it. Within a context we do context switching and within it we do the actual behavior testing.

describe("summary...", function()
  local data = {{'Foo'}, {'Bar'}, {'Baz'}}
  context("summary...", data, function(name)
    it("summary...", function()

When testdata are available each entry in the table will be provided to the provided callback in turn.

Insulate & expose

All code will be exposed, and only way to insulate a test is to run it on a separate pickle page.


There are no randomization of tests in the , although this will be possible in the refactored version.


The style used in the prototype is the usual describe - context - it, where arguments are a summary for the test, optional arguments for the test, and the actual test. The summary is either a string or a table. If it is a string it is assumed to be in the language of the wiki, if it is a table language specific summaries are keyed by language codes and tags are indexed in no particular order. The actual test is always a function, usually an anonymous one, and always the last argument.

describe("foo", function()
  context("bar", function()
    it("baz", function()


The call pending() can't be implemented as pure Lua, so instead change the ordinary wrappers to an exclude variant.

xdescribe('string', function() end)

Seems like Rspec does a shortcut: “When RSpec encounters this block it actually executes the block. If the block fails or raises an error, RSpec proceeds as with any other pending example.”


Summary strings might be either singular and assumed to be in the wikis own content language

describe("this is a summary", function() end)

or it might be in explicitly given languages

describe({en="this is a summary", no="dette er et sammendrag"}, function() end)

An indexed string in the array that isn't a valid tag is assumed to be a summary in the wikis own content language.


Summary strings may take tags. It is not necessary to declare tags

describe("a test #tag", function()
  -- tests go here

describe("a nested block #foo", function()
  context("can have many levels #bar", function()
    it("can have many levels #baz", function()
      -- more tests go here
  -- more tests pertaining to the top-level

Children will inherit parents tags. In the above the context will inherit the tag #foo from the second describe, and the it will inherit bot #foo and #bar from previous parents.

Tags can be added either in the summary string or on indexed entries in the array

describe("this is a summary #foo #bar #baz", function() end)
describe({"this is a summary", "#foo", "#bar", "#baz"}, function() end)
describe({en="this is a summary #foo #bar #baz"}, function() end)
describe({en="this is a summary", "#foo", "#bar", "#baz"}, function() end)

All indexed strings that is fully valid tags will be added as such and not as summary strings.

From wikitext the tests can be filtered on tags like so



Tracking categories would be set up for modules with and without tests. Those with tests will be good, pending and failed. Or would this be only for indicators?


Page indicators are inserted for all modules that has functions. There are two different messages, one for pickles and one for all the others.

Color scheme and symbols are implemented by the Lua scripts that run as part of the parsed messages.

Linked to the actual tests.

generated by LDoc 1.4.6