Skip to content

Instantly share code, notes, and snippets.

@ishubin
Last active August 29, 2015 14:16
Show Gist options
  • Select an option

  • Save ishubin/8ea58f3e24c456972a90 to your computer and use it in GitHub Desktop.

Select an option

Save ishubin/8ea58f3e24c456972a90 to your computer and use it in GitHub Desktop.
Draft for Galen Specs Language v2
#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"
#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