Skip to content

Commit

Permalink
Implemented focused tests. Closes #185.
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Dec 1, 2016
1 parent d04dfa4 commit 795a77e
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 26 deletions.
66 changes: 66 additions & 0 deletions fixtures/focused.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

describe('Suite with focused sub-suites', function() {
it('should not run a normal test', function () {
throw new RuntimeException();
});

xit('should not run a pending test', function () {
throw new RuntimeException();
});

describe('a normal suite', function () {
it('should not be run', function () {
throw new RuntimeException();
});
});

xdescribe('a pending suite', function () {
it('should not be run', function () {
throw new RuntimeException();
});
});

fit('should run a focused test', function () {});

fdescribe('a focused suite', function () {
it('should run each test', function () {});
it('should run each test', function () {});

xit('should allow pending tests', function () {
throw new RuntimeException();
});

xdescribe('a nested pending suite', function () {
it('should have pending child tests', function () {
throw new RuntimeException();
});
});
});

fdescribe('a focused suite with nested focused tests', function () {
it('should not run unfocused tests', function () {
throw new RuntimeException();
});

fit('should run focused tests', function () {});
});

describe('an unfocused suite with nested focused tests', function () {
it('should not run unfocused tests', function () {
throw new RuntimeException();
});

fit('should run focused tests', function () {});
});

xdescribe('a pending suite with nested focused tests', function () {
it('should not run unfocused child tests', function () {
throw new RuntimeException();
});

fit('should mark focused child tests as pending', function () {
throw new RuntimeException();
});
});
});
28 changes: 24 additions & 4 deletions specs/context.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,26 @@
assert($tests[1] === $sibling2, "sibling2 should have been added to parent");
});

it("should set pending if value is not null", function() {
it("should set pending if pending value is not null", function() {
$suite = $this->context->addSuite("desc", function() {}, true);
assert($suite->getPending(), "suite should be pending");
});

it("should ignore pending if value is null", function() {
it("should ignore pending if pending value is null", function() {
$suite = $this->context->addSuite("desc", function() {});
assert(is_null($suite->getPending()), "pending status should be null");
});

it("should set focused if focused value is supplied", function() {
$suite = $this->context->addSuite("desc", function() {}, null, true);
assert($suite->isFocused(), "suite should be focused");
});

it("should set focused to false if focused value is not supplied", function() {
$suite = $this->context->addSuite("desc", function() {});
assert(!$suite->isFocused(), "focused status should be false");
});

it("should execute a suites bound definition", function() {
$suite = $this->context->addSuite("desc", function() {
$this->value = "hello";
Expand All @@ -54,12 +64,12 @@
});

describe('->addTest()', function() {
it("should set pending status if value is not null", function() {
it("should set pending status if pending value is not null", function() {
$test = $this->context->addTest("is a spec", function() {}, true);
assert($test->getPending(), "pending status should be true");
});

it("should ignore pending status if value is null", function() {
it("should ignore pending status if pending value is null", function() {
$test = $this->context->addTest("is a spec", function() {});
assert(is_null($test->getPending()), "pending status should be null");
});
Expand All @@ -69,6 +79,16 @@
assert($test->getPending(), "pending status should be true");
});

it("should set focused status if focused value is supplied", function() {
$test = $this->context->addTest("is a spec", function() {}, null, true);
assert($test->isFocused(), "focused status should be true");
});

it("should set focused status if focused value is supplied", function() {
$test = $this->context->addTest("is a spec", function() {});
assert(!$test->isFocused(), "focused status should be false");
});

it('should increase size of root suite', function () {
$this->context->addTest('spec', function () { });
$suite = $this->context->getCurrentSuite();
Expand Down
64 changes: 64 additions & 0 deletions specs/suite.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
$this->eventEmitter = new EventEmitter();
});

context("when constructed with default parameters", function() {
it("it should default to an unfocused state", function() {
$suite = new Suite("Suite", function() {});
assert(!$suite->isFocused(), "suite should not be focused if focused value is not supplied");
});
});

describe('->run()', function() {
it("should run multiple tests", function () {
$suite = new Suite("Suite", function() {});
Expand Down Expand Up @@ -138,6 +145,23 @@

assert($result->getTestCount() == 2, "test count should be 2");
});

context('when there are focused tests', function() {
it("should run only the focused tests", function () {
$suite = new Suite("Suite", function() {});
$suite->addTest(new ItWasRun("should pass", function () {}, true));
$suite->addTest(new ItWasRun('should fail', function () {
throw new \Exception('woooooo!');
}, true));
$suite->addTest(new ItWasRun("should not be run", function () {}));
$suite->addTest(new ItWasRun("should also not be run", function () {}));

$result = new TestResult($this->eventEmitter);
$suite->setEventEmitter($this->eventEmitter);
$suite->run($result);
assert('2 run, 1 failed' == $result->getSummary(), "result summary should show 2/1");
});
});
});

describe("->addTest()", function() {
Expand Down Expand Up @@ -197,6 +221,46 @@
assert($this->arg === 1, 'should have set definition arguments');
});
});

describe('->isFocused()', function() {
context('when explicitly marked as focused', function () {
beforeEach(function() {
$this->suite = new Suite("test suite", function() {}, true);
});

it('should return true even if nested tests are not focused', function() {
$test = new Test("test", function() {});
$this->suite->addTest($test);
assert($this->suite->isFocused(), "suite should be focused");
});
});

context('when not explicitly marked as focused', function () {
beforeEach(function() {
$this->suite = new Suite("test suite", function() {});
});

it('should return false if nested tests are not focused', function() {
$test = new Test("test", function() {});
$this->suite->addTest($test);
assert(!$this->suite->isFocused(), "suite should not be focused");
});

it('should return true if nested tests are focused', function() {
$test = new Test("test", function() {}, true);
$this->suite->addTest($test);
assert($this->suite->isFocused(), "suite should be focused");
});

it('should return true if nested suites are focused', function() {
$suite = new Suite("nested suite", function() {});
$test = new Test("test", function() {}, true);
$suite->addTest($test);
$this->suite->addTest($suite);
assert($this->suite->isFocused(), "suite should be focused");
});
});
});
});

class SuiteScope extends Scope
Expand Down
2 changes: 1 addition & 1 deletion specs/suiteloader.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
describe('->getTests()', function() {
it("should return file paths matching *.spec.php recursively", function() {
$tests = $this->loader->getTests($this->fixtures);
assert(count($tests) == 4, "suite loader should have loaded 4 specs");
assert(count($tests) == 5, "suite loader should have loaded 5 specs");
});

it("should return single file if it exists", function() {
Expand Down
7 changes: 6 additions & 1 deletion specs/test.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@

describe("Test", function() {

context("when constructed with null definition", function() {
context("when constructed with default parameters", function() {
it("it should default to a pending state", function() {
$test = new Test("it should be pending");
assert($test->getPending(), "test should be pending if definition is null");
});

it("it should default to an unfocused state", function() {
$test = new Test("it should not be focused");
assert(!$test->isFocused(), "test should not be focused if focused value is not supplied");
});
});

describe('->run()', function() {
Expand Down
9 changes: 8 additions & 1 deletion src/Core/AbstractTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ abstract class AbstractTest implements TestInterface
*/
protected $pending = null;

/**
* @var bool
*/
protected $focused;

/**
* @var Scope
*/
Expand All @@ -65,11 +70,13 @@ abstract class AbstractTest implements TestInterface
/**
* @param string $description
* @param callable $definition
* @param bool $focused
*/
public function __construct($description, callable $definition)
public function __construct($description, callable $definition, $focused = false)
{
$this->definition = $definition;
$this->description = $description;
$this->focused = $focused;
$this->scope = new Scope();
}

Expand Down
38 changes: 36 additions & 2 deletions src/Core/Suite.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ class Suite extends AbstractTest
*/
protected $halted = false;

/**
* {@inheritdoc}
*
* @return bool
*/
public function isFocused()
{
if ($this->focused === true) {
return $this->focused;
}

foreach ($this->tests as $test) {
if ($test->isFocused()) {
return true;
}
}

return false;
}

/**
* Add a test to the suite
*
Expand Down Expand Up @@ -74,14 +94,14 @@ public function run(TestResult $result)
$this->eventEmitter->emit('suite.start', [$this]);
$this->eventEmitter->on('suite.halt', [$this, 'halt']);

foreach ($this->tests as $test) {

foreach ($this->getTestsToRun() as $test) {
if ($this->halted) {
break;
}

$this->runTest($test, $result);
}

$this->eventEmitter->emit('suite.end', [$this]);
}

Expand Down Expand Up @@ -111,4 +131,18 @@ protected function runTest(TestInterface $test, TestResult $result)
$test->setEventEmitter($this->eventEmitter);
$test->run($result);
}

/**
* Get the subset of the defined tests that should actually be run.
*
* @return array
*/
protected function getTestsToRun()
{
$tests = array_filter($this->tests, function (TestInterface $test) {
return $test->isFocused();
});

return empty($tests) ? $this->tests : $tests;
}
}
14 changes: 12 additions & 2 deletions src/Core/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,25 @@ class Test extends AbstractTest
* @param string $description
* @param callable $definition
*/
public function __construct($description, callable $definition = null)
public function __construct($description, callable $definition = null, $focused = false)
{
if ($definition === null) {
$this->pending = true;
$definition = function () {
//noop
};
}
parent::__construct($description, $definition);
parent::__construct($description, $definition, $focused);
}

/**
* {@inheritdoc}
*
* @return bool
*/
public function isFocused()
{
return $this->focused;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions src/Core/TestInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ public function getPending();
*/
public function setPending($state);

/**
* Return whether or not the test is focused
*
* @return bool
*/
public function isFocused();

/**
* Return scope for this test. Scope contains instance variables
* for a spec
Expand Down
Loading

0 comments on commit 795a77e

Please sign in to comment.