Starting work on spec files

This commit is contained in:
Jeff Avallone 2014-12-16 16:08:36 -05:00
parent f69d24e302
commit 5537928a80
3 changed files with 386 additions and 67 deletions

View File

@ -1,28 +0,0 @@
import parser from 'src/js/parser/javascript.js';
describe('parser/javascript.peg', function() {
describe('regular expression literals', function() {
describe('flags support', function() {
it('handles the ignore case flag', function() {
expect(parser.parse('/test/i').flags().ignore_case).toEqual(true);
expect(parser.parse('/test/').flags().ignore_case).toEqual(false);
});
it('handles the global flag', function() {
expect(parser.parse('/test/g').flags().global).toEqual(true);
expect(parser.parse('/test/').flags().global).toEqual(false);
});
it('handles the multiline flag', function() {
expect(parser.parse('/test/m').flags().multiline).toEqual(true);
expect(parser.parse('/test/').flags().multiline).toEqual(false);
});
});
});
});

333
spec/regexper_spec.js Normal file
View File

@ -0,0 +1,333 @@
import Regexper from 'src/js/regexper.js';
import Q from 'q';
describe('regexper.js', function() {
beforeEach(function() {
this.root = document.createElement('div');
this.root.innerHTML = [
'<form id="regexp-form" action="/"><input type="text" id="regexp-input" /></form>',
'<div id="error"></div>',
'<div><a href="#" data-glyph="link-intact"></a></div>',
'<div><a href="#" data-glyph="data-transfer-download"></a></div>',
'<div id="progress"><div></div></div>',
'<div id="regexp-render"><svg></svg></div>'
].join('');
this.regexper = new Regexper(this.root);
spyOn(this.regexper, '_setHash');
spyOn(this.regexper, '_getHash').and.returnValue('example hash value');
});
describe('#keypressListener', function() {
beforeEach(function() {
this.event = document.createEvent('Event');
spyOn(this.event, 'preventDefault');
spyOn(this.regexper.form, 'dispatchEvent');
});
describe('when the shift key is not depressed', function() {
beforeEach(function() {
this.event.shiftKey = false;
this.event.keyCode = 13;
});
it('does not prevent the default action', function() {
this.regexper.keypressListener(this.event);
expect(this.event.returnValue).not.toEqual(false);
expect(this.event.preventDefault).not.toHaveBeenCalled();
});
it('does not trigger a submit event', function() {
this.regexper.keypressListener(this.event);
expect(this.regexper.form.dispatchEvent).not.toHaveBeenCalled();
});
});
describe('when the keyCode is not 13 (Enter)', function() {
beforeEach(function() {
this.event.shiftKey = true;
this.event.keyCode = 42;
});
it('does not prevent the default action', function() {
this.regexper.keypressListener(this.event);
expect(this.event.returnValue).not.toEqual(false);
expect(this.event.preventDefault).not.toHaveBeenCalled();
});
it('does not trigger a submit event', function() {
this.regexper.keypressListener(this.event);
expect(this.regexper.form.dispatchEvent).not.toHaveBeenCalled();
});
});
describe('when the shift key is depressed and the keyCode is 13 (Enter)', function() {
beforeEach(function() {
this.event.shiftKey = true;
this.event.keyCode = 13;
});
it('prevents the default action', function() {
this.regexper.keypressListener(this.event);
expect(this.event.returnValue).not.toEqual(true);
expect(this.event.preventDefault).toHaveBeenCalled();
});
it('triggers a submit event', function() {
var event;
this.regexper.keypressListener(this.event);
expect(this.regexper.form.dispatchEvent).toHaveBeenCalled();
event = this.regexper.form.dispatchEvent.calls.mostRecent().args[0];
expect(event.type).toEqual('submit');
});
});
});
describe('#submitListener', function() {
beforeEach(function() {
this.event = document.createEvent('Event');
spyOn(this.event, 'preventDefault');
this.regexper.field.value = 'example value';
});
it('prevents the default action', function() {
this.regexper.submitListener(this.event);
expect(this.event.returnValue).not.toEqual(true);
expect(this.event.preventDefault).toHaveBeenCalled();
});
it('sets the location.hash', function() {
this.regexper.submitListener(this.event);
expect(this.regexper._setHash).toHaveBeenCalledWith('example value');
});
describe('when setting location.hash fails', function() {
beforeEach(function() {
this.regexper._setHash.and.throwError('hash failure');
});
it('disables the permalink', function() {
this.regexper.submitListener(this.event);
expect(this.regexper.permalinkEnabled).toEqual(false);
});
it('shows the expression directly', function() {
spyOn(this.regexper, 'showExpression');
this.regexper.submitListener(this.event);
expect(this.regexper.showExpression).toHaveBeenCalledWith('example value');
});
});
});
describe('#hashchangeListener', function() {
it('enables the permalink', function() {
this.regexper.hashchangeListener();
expect(this.regexper.permalinkEnabled).toEqual(true);
});
it('shows the expression from the hash', function() {
spyOn(this.regexper, 'showExpression');
this.regexper.hashchangeListener();
expect(this.regexper.showExpression).toHaveBeenCalledWith('example hash value');
});
});
describe('#updatePercentage', function() {
beforeEach(function() {
this.event = document.createEvent('Event');
this.event.detail = { percentage: 0.42 };
});
it('sets the width of the progress bar', function() {
this.regexper.updatePercentage(this.event);
expect(this.regexper.percentage.style.width).toEqual('42%');
});
});
describe('#bindListeners', function() {
it('binds #keypressListener to keypress on the text field', function() {
spyOn(this.regexper.field, 'addEventListener');
spyOn(this.regexper, 'keypressListener');
this.regexper.bindListeners();
expect(this.regexper.field.addEventListener).toHaveBeenCalledWith('keypress', jasmine.any(Function));
this.regexper.field.addEventListener.calls.mostRecent().args[1]();
expect(this.regexper.keypressListener).toHaveBeenCalled();
});
it('binds #submitListener to submit on the form', function() {
spyOn(this.regexper.form, 'addEventListener');
spyOn(this.regexper, 'submitListener');
this.regexper.bindListeners();
expect(this.regexper.form.addEventListener).toHaveBeenCalledWith('submit', jasmine.any(Function));
this.regexper.form.addEventListener.calls.mostRecent().args[1]();
expect(this.regexper.submitListener).toHaveBeenCalled();
});
it('binds #updatePercentage to updateStatus on the root', function() {
spyOn(this.regexper.root, 'addEventListener');
spyOn(this.regexper, 'updatePercentage');
this.regexper.bindListeners();
expect(this.regexper.root.addEventListener).toHaveBeenCalledWith('updateStatus', jasmine.any(Function));
this.regexper.root.addEventListener.calls.mostRecent().args[1]();
expect(this.regexper.updatePercentage).toHaveBeenCalled();
});
it('binds #hashchangeListener to hashchange on the window', function() {
spyOn(window, 'addEventListener');
spyOn(this.regexper, 'hashchangeListener');
this.regexper.bindListeners();
expect(window.addEventListener).toHaveBeenCalledWith('hashchange', jasmine.any(Function));
window.addEventListener.calls.mostRecent().args[1]();
expect(this.regexper.hashchangeListener).toHaveBeenCalled();
});
});
describe('#showExpression', function() {
beforeEach(function() {
this.renderPromise = Q.defer();
spyOn(this.regexper, 'renderRegexp').and.returnValue(this.renderPromise.promise);
});
it('sets the text field value', function() {
this.regexper.showExpression('example expression');
expect(this.regexper.field.value).toEqual('example expression');
});
describe('when the expression is blank', function() {
it('clears the state', function() {
this.regexper.showExpression('');
expect(this.regexper.state).toEqual('');
});
});
describe('when the expression is not blank', function() {
it('sets the state to "is-loading"', function() {
this.regexper.showExpression('example expression');
expect(this.regexper.state).toEqual('is-loading');
});
it('renders the expression', function() {
this.regexper.showExpression('example expression');
expect(this.regexper.renderRegexp).toHaveBeenCalledWith('example expression');
});
describe('when the expression finishes rendering', function() {
beforeEach(function(done) {
spyOn(this.regexper, 'updateLinks');
this.regexper.showExpression('example expression');
this.renderPromise.resolve();
setTimeout(done, 100);
});
it('sets the state to "has-results"', function() {
expect(this.regexper.state).toEqual('has-results');
});
it('updates the links', function() {
expect(this.regexper.updateLinks).toHaveBeenCalled();
});
});
});
});
describe('#updateLinks', function() {
beforeEach(function() {
spyOn(this.regexper, 'buildBlobURL');
});
describe('when blob URLs are supported', function() {
beforeEach(function() {
this.regexper.buildBlobURL.and.returnValue('http://example.com/blob');
});
it('sets the download link href', function() {
this.regexper.updateLinks();
expect(this.regexper.download.href).toEqual('http://example.com/blob');
});
});
describe('when blob URLs are not supported', function() {
beforeEach(function() {
this.regexper.buildBlobURL.and.throwError('blob failure');
});
it('hides the download link', function() {
this.regexper.updateLinks();
expect(this.regexper.download.parentNode.style.display).toEqual('none');
});
});
describe('when the permalink is enabled', function() {
beforeEach(function() {
this.regexper.permalinkEnabled = true;
});
it('sets the permalink href', function() {
this.regexper.updateLinks();
expect(this.regexper.permalink.href).toEqual(location.toString());
});
});
describe('when the permalink is disabled', function() {
beforeEach(function() {
this.regexper.permalinkEnabled = false;
});
it('hides the permalink', function() {
this.regexper.updateLinks();
expect(this.regexper.permalink.parentNode.style.display).toEqual('none');
});
});
});
describe('#renderRegexp', function() {
});
});

View File

@ -33,40 +33,25 @@ export default class Regexper {
}
submitListener(event) {
event.preventDefault();
event.returnValue = false;
if (event.preventDefault) {
event.preventDefault();
}
try {
this.disablePermalink = false;
location.hash = this.field.value;
this._setHash(this.field.value);
}
catch(e) {
// Most likely failed to set the URL has (probably because the expression
// is too long). Turn off the permalink and just show the expression
this.disablePermalink = true;
this.permalinkEnabled = false;
this.showExpression(this.field.value);
}
}
hashchangeListener() {
var expression = decodeURIComponent(location.hash.slice(1));
this.showExpression(expression);
}
showExpression(expression) {
this.field.value = expression;
this.state = '';
if (expression !== '') {
this.state = 'is-loading';
this.renderRegexp(expression.replace(/\n/g, '\\n'))
.then(() => {
this.state = 'has-results';
this.updateLinks();
})
.done();
}
this.permalinkEnabled = true;
this.showExpression(this._getHash());
}
updatePercentage(event) {
@ -80,27 +65,50 @@ export default class Regexper {
window.addEventListener('hashchange', this.hashchangeListener.bind(this));
}
_setHash(hash) {
location.hash = encodeURIComponent(hash);
}
_getHash() {
return decodeURIComponent(location.hash.slice(1));
}
set state(state) {
this.root.className = state;
}
showError(message) {
this.state = 'has-error';
this.error.innerHTML = '';
this.error.appendChild(document.createTextNode(message));
get state() {
return this.root.className;
}
throw message;
showExpression(expression) {
this.field.value = expression;
this.state = '';
if (expression !== '') {
this.state = 'is-loading';
this.renderRegexp(expression)
.then(() => {
this.state = 'has-results';
this.updateLinks();
})
.done();
}
}
buildBlobURL(content) {
blob = new Blob([content], { type: 'image/svg+xml' });
window.blob = blob; // Blob object has to stick around for IE
return URL.createObjectURL(blob);
}
updateLinks() {
var blob, url;
try {
blob = new Blob([this.svg.parentNode.innerHTML], { type: 'image/svg+xml' });
url = URL.createObjectURL(blob);
window.blob = blob; // Blob object has to stick around for IE
this.download.setAttribute('href', url);
this.download.parentNode.style.display = null;
this.download.href = this.buildBlobURL(this.svg.parentNode.innerHTML);
}
catch(e) {
// Blobs or URLs created from them don't work here.
@ -108,11 +116,11 @@ export default class Regexper {
this.download.parentNode.style.display = 'none';
}
if (this.disablePermalink) {
this.permalink.parentNode.style.display = 'none';
} else {
if (this.permalinkEnabled) {
this.permalink.parentNode.style.display = null;
this.permalink.setAttribute('href', location.toString());
this.permalink.href = location.toString();
} else {
this.permalink.parentNode.style.display = 'none';
}
}
@ -123,8 +131,14 @@ export default class Regexper {
parser.resetGroupCounter();
return Q.fcall(parser.parse.bind(parser), expression)
.then(null, this.showError.bind(this))
return Q.fcall(parser.parse.bind(parser), expression.replace(/\n/g, '\\n'))
.then(null, message => {
this.state = 'has-error';
this.error.innerHTML = '';
this.error.appendChild(document.createTextNode(message));
throw message;
})
.invoke('render', snap.group())
.then(result => {
var box;