Last active
August 29, 2015 14:16
-
-
Save ishubin/8ea58f3e24c456972a90 to your computer and use it in GitHub Desktop.
Draft for Galen Specs Language v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #galen|spec|v2 | |
| # in the new spec lang v2 everything will be done based on indentation | |
| # All sections will have their own structure | |
| # | |
| # Also we will get rid of '@@' symbols for importing, conditions, rules etc. | |
| # | |
| # Objects definition | |
| # ~~~~~~~~~~~~~~~~~~ | |
| # Object defition will start with special keyword "objects" | |
| # It will be possible to represent the object in hierarchical structure using indentation | |
| objects | |
| header id header | |
| icon css img.icon | |
| caption css h2 | |
| login-button .login-button | |
| menu-item-* #menu li | |
| # You will be able to use the "icon" and "caption" objects form above via their full names "header.icon" and "header.caption" | |
| # Importing | |
| # ~~~~~~~~~~~~~~~~~ | |
| # importing other page specs will be allowed only on the highest level. It will not be bound to any sections. | |
| import somePage.spec | |
| # or like this | |
| import | |
| somePage.spec | |
| anotherPage.spec | |
| # or like this | |
| import somePage.spec, anotherPage.spec | |
| # Sections | |
| # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| # Each section should be defined with '-' symbol in its beginning and at the end. | |
| # Each section can have multi-level sections inside it | |
| # And each sub-section can have its own tags | |
| # By default if you don't specify tags - a section without tags will match any tag during validation | |
| # The tags are defined inside "@( ... )" statement and everything else is considered as a name of a section | |
| # if a section does not have a name (empty name) then all of its contents will be unwraped to a higher level | |
| # | |
| # For example below you can see that we defined a "Header" section and it has two subsections which match different tags | |
| - Header - | |
| - @( mobile, tablet) - | |
| header : | |
| inside screen 10px top left | |
| # as you can see we will omit ':' symbol inside specs to make it more readable | |
| # just so that the parser would be able to understand where | |
| # are special instructions like import, script and where is a test object | |
| # we are adding ':' symbol to the end of each test object definition | |
| # this way we know that we have started building up test objects | |
| header-icon : | |
| inside header 10px top left bottom | |
| |squared | |
| # Also it should be possible to create aliases for object specs to make them more understandable | |
| # It will not have any logic. This aliases will be used in html report | |
| # This can be done with double-quotes | |
| # The problem which it could solve was stated by Shawn Erquhart in https://github.com/galenframework/galen/issues/108 | |
| header-text : | |
| "should be 100 pixels width" width 98 to 101 px | |
| - @( desktop ) - | |
| - Another section - | |
| header-text : | |
| text is "Hi there!" | |
| # for text and css checks we can use double-quotes or omit them. | |
| - Boxes section @(desktop, tablet) - | |
| box-section-* : | |
| aligned horizontally all box-section-1 | |
| # this is an example of rule being called. The rule is defined below | |
| | box-section-* should all be equally distant from each other | |
| # Loops | |
| # ~~~~~~~~~~~~~~~~~~~ | |
| # There will be two ways of looping | |
| # - forEach - will allow complex iteration and mapping to name, index, next element name, previous element name | |
| # - for - will work the same way as in first spec version via [...] but it will allow mapping item to a custom variable | |
| - Footer - | |
| forEach box-section-* as name | |
| ${name} : | |
| height 40 to 50 px | |
| forEach box-section-* until penult as name, index, next, prev | |
| ${name} : | |
| near box-section-${index + 1} 10px left | |
| near ${next} 10px left | |
| # or you can check with previous element | |
| forEach box-section-* from second until last as name, , , prev | |
| ${name} : | |
| near ${prev} 10px right | |
| for [1 - 8, 12, 13] as index | |
| box-section-${index} : | |
| near box-section-${index + 1} 10px left | |
| # and this is the example of the loop inside another loop | |
| for [1 - 10] as index2 | |
| item-${index2} : | |
| above box-section-${index} | |
| # using script | |
| # in here it creates a fule from script | |
| script | |
| rule("%{objectPattern} should all be equally distant from each other", function (objectName, params) { | |
| var objects = findAll(params.objectPattern); | |
| var distance = objects[1].left(); - objects[0].right(); | |
| for (var i = 2; i < objects.length; i++) { | |
| this.addObjectSpecs(objects[i], [ | |
| "near: " + objects[i - 1] + " " + distance + "px right"; | |
| ]); | |
| } | |
| }); | |
| rule squared | |
| width 100% of ${objectName}/height | |
| # same rule written with javascript | |
| # function addSpecs can only be used in case the rule is simple and used for a specific object | |
| script | |
| rule("squared", function (objectName, params) { | |
| this.addSpecs([ | |
| "width 100% of " + objectName + "/height" | |
| ]); | |
| }); | |
| # or a script could also be called via file path | |
| script some-custom.js | |
| # conditions | |
| # ~~~~~~~~~~~~~~~~ | |
| if | |
| banner-1 : | |
| visible | |
| or not | |
| banner-2 : | |
| visible | |
| do | |
| banner-1 : | |
| height 100px | |
| width 500px | |
| otherwise | |
| banner-2 : | |
| height 30px | |
| width 500px | |
| # either constructions | |
| # ~~~~~~~~~~~~~~~~~~~~~~ | |
| either | |
| banner-1 : | |
| visible | |
| or | |
| banner-2 : | |
| visible | |
| # Testing global things | |
| # ~~~~~~~~~~~~~~~~~~~~~ | |
| check count menu-item-* is 10 | |
| check count menu-item-* is > 10 | |
| check count menu-item-* is < 10 | |
| check count menu-item-* is 10 to 20 | |
| check title is "Some Website" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #galen|spec|v2 | |
| # Just another example of GalenSpecs language | |
| # In this version of GalenSpec language all special keywords will be defined with '@' symbol | |
| # This way it should be easier to distinguish between object notation and special keyword | |
| # | |
| # Here is a list of some special keywords: | |
| # - @objects | |
| # - @import | |
| # - @script | |
| # - @for | |
| # - @forEach | |
| # - @forEachObject | |
| # - @if | |
| # - @or | |
| # - @otherwise | |
| # - ... | |
| @objects | |
| header id header | |
| icon css img.icon | |
| caption css h2 | |
| login-button .login-button | |
| menu-item-* #menu li | |
| @import somePage.spec | |
| @import somePage.spec, anotherPage.spec | |
| # Setting variables | |
| @set var1 var value | |
| # Setting variables | |
| @set | |
| var1 var value | |
| var2 second var value | |
| # Sections | |
| # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| # Each section should be defined with '=' symbol in its beginning and at the end. | |
| # Each section can have multi-level sections inside it | |
| # And each sub-section can have its own tags | |
| # By default if you don't specify tags - a section without tags will match any tag during validation | |
| # The tags are defined inside "@( ... )" statement and everything else is considered as a name of a section | |
| # if a section does not have a name (empty name) then all of its contents will be unwraped to a higher level | |
| # | |
| # For example below you can see that we defined a "Header" section and it has two subsections which match different tags | |
| = Header = | |
| = @( mobile, tablet) = | |
| header : | |
| - inside screen 10px top left | |
| # as you can see we will omit ':' symbol inside specs to make it more readable | |
| # we are adding ':' symbol to the end of each test object definition | |
| # this way we know that we have started building up test objects | |
| header-icon : | |
| - inside header 10px top left bottom | |
| % height 100px | |
| | squared | |
| header-text : | |
| - "should be 100 pixels width" width 98 to 101 px | |
| = @( desktop ) = | |
| = Another section = | |
| header-text : | |
| - text is "Hi there!" | |
| # for text and css checks we can use double-quotes or omit them. | |
| = Boxes section @(desktop, tablet) = | |
| box-section-* : | |
| - aligned horizontally all box-section-1 | |
| # this is an example of rule being called. The rule is defined below | |
| | box-section-* should all be equally distant from each other | |
| # Loops | |
| # ~~~~~~~~~~~~~~~~~~~ | |
| # There will be two ways of looping | |
| # - forEach - will allow complex iteration and mapping to name, index, next element name, previous element name | |
| # - for - will work the same way as in first spec version via [...] but it will allow mapping item to a custom variable | |
| = Footer = | |
| @forEach box-section-* as name | |
| ${name} : | |
| - height 40 to 50 px | |
| @forEachObject box-section-* until penult as index:i, next:nextElement | |
| - height 40 to 50 px | |
| @forEach box-section-* until penult as name:objectName, index:index, next, prev | |
| ${objectName} : | |
| - near box-section-${index + 1} 10px left | |
| - near ${next} 10px left | |
| # or you can check with previous element | |
| @forEach box-section-* from second until last as name, prev | |
| ${name} : | |
| - near ${prev} 10px right | |
| @for [1 - 8, 12, 13] as index | |
| box-section-${index} : | |
| - near box-section-${index + 1} 10px left | |
| # and this is the example of the loop inside another loop | |
| @for [1 - 10] as index2 | |
| item-${index2} : | |
| - above box-section-${index} | |
| # using script | |
| # in here it creates a fule from script | |
| @script | |
| rule("%{objectPattern} should all be equally distant from each other", function (objectName, params) { | |
| var objects = findAll(params.objectPattern); | |
| var distance = objects[1].left(); - objects[0].right(); | |
| for (var i = 2; i < objects.length; i++) { | |
| this.addObjectSpecs(objects[i], [ | |
| "near: " + objects[i - 1] + " " + distance + "px right"; | |
| ]); | |
| } | |
| }); | |
| @rule squared | |
| - width 100% of ${objectName}/height | |
| # same rule written with javascript | |
| # function addSpecs can only be used in case the rule is simple and used for a specific object | |
| @script | |
| rule("squared", function (objectName, params) { | |
| this.addSpecs([ | |
| "width 100% of " + objectName + "/height" | |
| ]); | |
| }); | |
| # or a script could also be called via file path | |
| @script some-custom.js | |
| # conditions | |
| # ~~~~~~~~~~~~~~~~ | |
| @if | |
| banner-1 : | |
| - visible | |
| @or not | |
| banner-2 : | |
| - visible | |
| @do | |
| banner-1 : | |
| - height 100px | |
| - width 500px | |
| @otherwise | |
| banner-2 : | |
| - height 30px | |
| - width 500px | |
| # either constructions | |
| # ~~~~~~~~~~~~~~~~~~~~~~ | |
| @either | |
| banner-1 : | |
| - visible | |
| @or | |
| banner-2 : | |
| - visible | |
| # Testing global things | |
| # ~~~~~~~~~~~~~~~~~~~~~ | |
| @check count menu-item-* is 10 | |
| @check count menu-item-* is > 10 | |
| @check count menu-item-* is < 10 | |
| @check count menu-item-* is 10 to 20 | |
| @check title is "Some Website" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment