Skip to content

Commit

Permalink
Added JS tests for yii.captcha.js (yiisoft#12840), fixes yiisoft#13159 (
Browse files Browse the repository at this point in the history
yiisoft#13160)

* Added JS tests for yii.captcha.js (yiisoft#12840), fixes yiisoft#13159

* Sinon needs to be imported in similar fashion in other test files

* Added according line to CHANGELOG [skip ci]

* Update CHANGELOG.md

* Try to run tests with default timeout in Travis

* Added note about JS tests to the docs [skip ci]

* Simplified tests for multiple elements (init, destroy methods)
  • Loading branch information
arogachev authored and SilverFire committed Dec 10, 2016
1 parent bd85b7c commit d963636
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 11 deletions.
16 changes: 15 additions & 1 deletion docs/internals/git-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ The following steps are not necessary if you want to work only on translations o

> Note: If you see errors like `Problem 1 The requested package bower-asset/jquery could not be found in any version, there may be a typo in the package name.`, you will need to run `composer global require "fxp/composer-asset-plugin:^1.2.0"`
If you are going to work with JavaScript:

- run `npm install` to install JavaScript testing tools and dependencies (assuming you have [Node.js and NPM installed]
(https://nodejs.org/en/download/package-manager/)).

> Note: JavaScript tests depend on [jsdom](https://github.com/tmpvar/jsdom) library which requires Node.js 4 or newer.
Using of Node.js 6 or 7 is more preferable.

- run `php build/build dev/app basic` to clone the basic app and install composer dependencies for the basic app.
This command will install foreign composer packages as normal but will link the yii2 repo to
the currently checked out repo, so you have one instance of all the code installed.
Expand All @@ -63,7 +71,13 @@ Some tests require additional databases to be set up and configured. You can cre
settings that are configured in `tests/data/config.php`.

You may limit the tests to a group of tests you are working on e.g. to run only tests for the validators and redis
`phpunit --group=validators,redis`. You get the list of available groups by running `phpunit --list-groups`.
`phpunit --group=validators,redis`. You get the list of available groups by running `phpunit --list-groups`.

You can execute JavaScript unit tests by running `npm test` in the repo root directory.

> Note: If you get timeout errors like `Error: timeout of 2000ms exceeded. Ensure the done() callback is being called
in this test.`, you can increase timeout: `npm test -- --timeout 30000` (don't miss `--`, it's needed for passing
additional arguments).

### Extensions

Expand Down
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Yii Framework 2 Change Log
- Bug #12974: Fixed incorrect order of migrations history in case `yii\console\controllers\MigrateController::$migrationNamespaces` is in use (evgen-d, klimov-paul)
- Bug #13071: Help option for commands was not working in modules (arogachev, haimanman)
- Bug #13089: Fixed `yii\console\controllers\AssetController::adjustCssUrl()` breaks URL reference specification (`url(#id)`) (vitalyzhakov)
- Bug #13159: Fixed `destroy` method in `yii.captcha.js` which did not work as expected (arogachev)
- Bug #7727: Fixed truncateHtml leaving extra tags (developeruz)
- Bug #13118: Fixed `handleAction()` function in `yii.js` to handle attribute `data-pjax=0` as disabled PJAX (silverfire)
- Enh #475: Added Bash and Zsh completion support for the `./yii` command (cebe, silverfire)
Expand Down
11 changes: 4 additions & 7 deletions framework/assets/yii.captcha.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha');
$.error('Method ' + method + ' does not exist in jQuery.yiiCaptcha');
return false;
}
};
Expand All @@ -39,7 +39,6 @@
methods.refresh.apply($e);
return false;
});

});
},

Expand All @@ -58,15 +57,13 @@
},

destroy: function () {
return this.each(function () {
$(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha');
});
this.off('.yiiCaptcha');
this.removeData('yiiCaptcha');
return this;
},

data: function () {
return this.data('yiiCaptcha');
}
};
})(window.jQuery);

151 changes: 151 additions & 0 deletions tests/js/tests/yii.captcha.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
var assert = require('chai').assert;
var sinon;
var withData = require('leche').withData;
var jsdom = require('mocha-jsdom');

var fs = require('fs');
var vm = require('vm');

describe('yii.captcha', function () {
var yiiCaptchaPath = 'framework/assets/yii.captcha.js';
var jQueryPath = 'vendor/bower/jquery/dist/jquery.js';
var $;
var $captcha;
var settings = {
refreshUrl: '/site/captcha?refresh=1',
hashKey: 'yiiCaptcha/site/captcha'
};

function registerTestableCode() {
var code = fs.readFileSync(yiiCaptchaPath);
var script = new vm.Script(code);
var context = new vm.createContext({window: window});

script.runInContext(context);
}

var imgHtml = '<img id="captcha" class="captcha" src="/site/captcha/">' +
'<img id="captcha-2" class="captcha" src="/site/captcha/">';
var html = '<!doctype html><html><head><meta charset="utf-8"></head><body>' + imgHtml + '</body></html>';

jsdom({
html: html,
src: fs.readFileSync(jQueryPath, 'utf-8')
});

before(function () {
$ = window.$;
registerTestableCode();
sinon = require('sinon');
});

afterEach(function () {
if ($captcha.length) {
$captcha.yiiCaptcha('destroy');
}
});

describe('init', function () {
var customSettings = {
refreshUrl: '/posts/captcha?refresh=1',
hashKey: 'yiiCaptcha/posts/captcha'
};

withData({
'no method specified': [function () {
$captcha = $('.captcha').yiiCaptcha(settings);
}, settings],
'no method specified, custom options': [function () {
$captcha = $('.captcha').yiiCaptcha(customSettings);
}, customSettings],
'manual method call': [function () {
$captcha = $('.captcha').yiiCaptcha('init', settings);
}, settings]
}, function (initFunction, expectedSettings) {
it('should save settings for all elements', function () {
initFunction();
assert.deepEqual($('#captcha').data('yiiCaptcha'), {settings: expectedSettings});
assert.deepEqual($('#captcha-2').data('yiiCaptcha'), {settings: expectedSettings});
});
});
});

describe('refresh', function () {
var server;
var response = {hash1: 747, hash2: 748, url: '/site/captcha?v=584696959e038'};

beforeEach(function () {
server = sinon.fakeServer.create();
window.XMLHttpRequest = global.XMLHttpRequest;
});

afterEach(function () {
server.restore();
});

withData({
'click on the captcha': [function () {
$captcha.trigger('click');
}],
'manual method call': [function () {
$captcha.yiiCaptcha('refresh');
}]
}, function (refreshFunction) {
it('should send ajax request, update the image and data for client-side validation', function () {
$captcha = $('#captcha').yiiCaptcha(settings);
refreshFunction();
server.requests[0].respond(200, {"Content-Type": "application/json"}, JSON.stringify(response));

assert.lengthOf(server.requests, 1);
assert.include(server.requests[0].url, settings.refreshUrl + '&_=');
assert.include(server.requests[0].requestHeaders.Accept, 'application/json');
assert.equal($captcha.attr('src'), response.url);
assert.deepEqual($('body').data(settings.hashKey), [response.hash1, response.hash2]);
});
});
});

describe('destroy method', function () {
var ajaxStub;

before(function () {
ajaxStub = sinon.stub($, 'ajax');
});

after(function () {
ajaxStub.restore();
});

var message = 'should remove event handlers with saved settings for destroyed element only and return ' +
'initial jQuery object';
it(message, function () {
$captcha = $('.captcha').yiiCaptcha(settings);
var $captcha1 = $('#captcha');
var $captcha2 = $('#captcha-2');
var destroyResult = $captcha1.yiiCaptcha('destroy');
$captcha1.trigger('click');
$captcha2.trigger('click');

assert.strictEqual(destroyResult, $captcha1);
assert.isTrue(ajaxStub.calledOnce);
assert.isUndefined($captcha1.data('yiiCaptcha'));
assert.deepEqual($captcha2.data('yiiCaptcha'), {settings: settings});
});
});

describe('data method', function () {
it('should return saved settings', function () {
$captcha = $('#captcha').yiiCaptcha(settings);
assert.deepEqual($captcha.yiiCaptcha('data'), {settings: settings});
});
});

describe('call of not existing method', function () {
it('should throw according error', function () {
$captcha = $('#captcha').yiiCaptcha(settings);
assert.throws(function () {
$captcha.yiiCaptcha('foobar');
}, 'Method foobar does not exist in jQuery.yiiCaptcha');
});
});
});
5 changes: 2 additions & 3 deletions tests/js/tests/yii.validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ assert.isDeferred = function (object) {
return String(object.resolve) === String($.Deferred().resolve);
};

var sinon = require('sinon');
var sinon;
var withData = require('leche').withData;

var StringUtils = {
Expand All @@ -25,8 +25,6 @@ var vm = require('vm');
var yii;

describe('yii.validation', function () {
this.timeout(15000);

var VALIDATOR_SUCCESS_MESSAGE = 'should leave messages as is';
var VALIDATOR_ERROR_MESSAGE = 'should add appropriate errors(s) to messages';

Expand Down Expand Up @@ -82,6 +80,7 @@ describe('yii.validation', function () {
before(function () {
$ = window.$;
registerTestableCode();
sinon = require('sinon');
});

it('should exist', function () {
Expand Down

0 comments on commit d963636

Please sign in to comment.