├── .gitignore ├── pom.xml └── src └── test ├── java └── com │ └── galenframework │ └── java │ └── sample │ ├── components │ └── GalenTestBase.java │ └── tests │ └── WelcomePageTest.java └── resources └── specs ├── addNotePage.spec ├── common.spec ├── loginPage-withErrorMessage.spec ├── loginPage.spec ├── menuHighlight.spec ├── myNotesPage.spec └── welcomePage.spec /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | .idea/ 4 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.galenframework 5 | galen-java-sample-tests 6 | 0.1-SNAPSHOT 7 | Galen Framework Sample Java Test Project 8 | jar 9 | A test project for testing Galen using Java-based tests 10 | 11 | 12 | 13 | org.hamcrest 14 | hamcrest-all 15 | 1.3 16 | test 17 | 18 | 19 | org.testng 20 | testng 21 | 6.7 22 | test 23 | 24 | 25 | com.galenframework 26 | galen-java-support 27 | 2.3.0 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 2.3.2 36 | 37 | 1.8 38 | 1.8 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-surefire-plugin 44 | 2.17 45 | 46 | 47 | usedefaultlistenersfalse 48 | 49 | listener 50 | com.galenframework.testng.GalenTestNgReportsListener 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | The Apache Software License, Version 2.0 61 | http://www.apache.org/licenses/LICENSE-2.0.txt 62 | manual 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/test/java/com/galenframework/java/sample/components/GalenTestBase.java: -------------------------------------------------------------------------------- 1 | package com.galenframework.java.sample.components; 2 | 3 | import com.galenframework.testng.GalenTestNgTestBase; 4 | import org.openqa.selenium.Dimension; 5 | import org.openqa.selenium.WebDriver; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | import org.testng.annotations.DataProvider; 8 | 9 | import java.util.List; 10 | 11 | import static java.util.Arrays.asList; 12 | 13 | public abstract class GalenTestBase extends GalenTestNgTestBase { 14 | 15 | private static final String ENV_URL = "http://testapp.galenframework.com"; 16 | 17 | @Override 18 | public WebDriver createDriver(Object[] args) { 19 | WebDriver driver = new FirefoxDriver(); 20 | if (args.length > 0) { 21 | if (args[0] != null && args[0] instanceof TestDevice) { 22 | TestDevice device = (TestDevice)args[0]; 23 | if (device.getScreenSize() != null) { 24 | driver.manage().window().setSize(device.getScreenSize()); 25 | } 26 | } 27 | } 28 | return driver; 29 | } 30 | 31 | public void load(String uri) { 32 | getDriver().get(ENV_URL + uri); 33 | } 34 | 35 | @DataProvider(name = "devices") 36 | public Object [][] devices () { 37 | return new Object[][] { 38 | {new TestDevice("mobile", new Dimension(450, 800), asList("mobile"))}, 39 | {new TestDevice("tablet", new Dimension(750, 800), asList("tablet"))}, 40 | {new TestDevice("desktop", new Dimension(1024, 800), asList("desktop"))} 41 | }; 42 | } 43 | 44 | public static class TestDevice { 45 | private final String name; 46 | private final Dimension screenSize; 47 | private final List tags; 48 | 49 | public TestDevice(String name, Dimension screenSize, List tags) { 50 | this.name = name; 51 | this.screenSize = screenSize; 52 | this.tags = tags; 53 | } 54 | 55 | public String getName() { 56 | return name; 57 | } 58 | 59 | public Dimension getScreenSize() { 60 | return screenSize; 61 | } 62 | 63 | public List getTags() { 64 | return tags; 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return String.format("%s %dx%d", name, screenSize.width, screenSize.height); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/galenframework/java/sample/tests/WelcomePageTest.java: -------------------------------------------------------------------------------- 1 | package com.galenframework.java.sample.tests; 2 | 3 | import com.galenframework.java.sample.components.GalenTestBase; 4 | import com.galenframework.java.sample.components.GalenTestBase; 5 | import org.openqa.selenium.By; 6 | import org.testng.annotations.Test; 7 | 8 | import java.io.IOException; 9 | 10 | 11 | public class WelcomePageTest extends GalenTestBase { 12 | 13 | @Test(dataProvider = "devices") 14 | public void welcomePage_shouldLookGood_onDevice(TestDevice device) throws IOException { 15 | load("/"); 16 | checkLayout("/specs/welcomePage.spec", device.getTags()); 17 | } 18 | 19 | @Test(dataProvider = "devices") 20 | public void loginPage_shouldLookGood_onDevice(TestDevice device) throws IOException { 21 | load("/"); 22 | getDriver().findElement(By.xpath("//button[.='Login']")).click(); 23 | checkLayout("/specs/loginPage.spec", device.getTags()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/resources/specs/addNotePage.spec: -------------------------------------------------------------------------------- 1 | @import common.spec 2 | 3 | @objects 4 | caption css #content h2 5 | title-textfield css input[name='note.title'] 6 | description-textfield css textarea 7 | button-add css button.btn-primary 8 | button-cancel css button.btn-default 9 | 10 | 11 | = Add note page = 12 | @on * 13 | caption: 14 | below menu 20 to 45 px 15 | inside content ~ 20px left right 16 | height 20 to 40px 17 | above title-textfield 10 to 20px 18 | aligned vertically all title-textfield 19 | 20 | title-textfield: 21 | inside content ~ 20px left right 22 | below caption 10 to 20px 23 | inside content ~ 20px left right 24 | height 25 to 40px 25 | above description-textfield 10 to 20px 26 | 27 | description-textfield: 28 | aligned vertically all title-textfield 29 | height 150 to 350px 30 | 31 | 32 | button-add, button-cancel: 33 | height 40 to 50px 34 | 35 | 36 | @on desktop, tablet 37 | button-add: 38 | width 80 to 140px 39 | aligned horizontally all button-cancel 40 | below description-textfield 10 to 20px 41 | aligned vertically left description-textfield 42 | 43 | button-cancel: 44 | near button-add 0 to 10px right 45 | width 80 to 140px 46 | 47 | 48 | 49 | @on mobile 50 | button-add, button-cancel: 51 | aligned vertically all description-textfield 52 | 53 | button-cancel: 54 | below button-add 10 to 20px -------------------------------------------------------------------------------- /src/test/resources/specs/common.spec: -------------------------------------------------------------------------------- 1 | 2 | @objects 3 | header css #header .middle-wrapper 4 | header-logo id header-logo 5 | header-text css #header h1 6 | menu css #menu ul 7 | menu-item-* css #menu li a 8 | content css #content 9 | footer id footer 10 | 11 | 12 | = Header = 13 | @on * 14 | header: 15 | inside screen 0px top 16 | centered horizontally inside screen 1px 17 | height ~ 70px 18 | 19 | header-logo: 20 | inside header 5 to 15px top, 0 to 10px left 21 | near header-text 5 to 30px left 22 | 23 | header-text: 24 | inside header 10 to 25px top 25 | 26 | @on desktop 27 | header: 28 | width 900px 29 | 30 | header-text: 31 | text is "Sample Website for Galen Framework" 32 | 33 | 34 | @on mobile, tablet 35 | header-text: 36 | text is "Sample Website" 37 | 38 | 39 | 40 | 41 | = Menu = 42 | menu: 43 | centered horizontally inside screen 1px 44 | below header ~ 0px 45 | 46 | 47 | @on desktop 48 | menu: 49 | width 900px 50 | 51 | 52 | @on desktop, tablet 53 | menu-item-1: 54 | inside menu ~ 0px top left bottom 55 | 56 | menu-item-*: 57 | width 90 to 130px 58 | height ~ 64px 59 | inside menu ~ 0px top 60 | 61 | @forEach [menu-item-*] as menuItem, prev as previousMenuItem 62 | ${menuItem}: 63 | right-of ${previousMenuItem} 0 to 5px 64 | aligned horizontally all ${previousMenuItem} 65 | 66 | 67 | @on mobile 68 | menu-item-* : 69 | width 48 to 50% of screen/width 70 | 71 | @for [ 1, 2 ] as index 72 | menu-item-${index}: 73 | above menu-item-${index + 2} 0 to 5px 74 | 75 | @for [ 1, 3 ] as index 76 | menu-item-${index}: 77 | near menu-item-${index + 1} 0 to 5 px left 78 | 79 | 80 | = Content = 81 | @on * 82 | content: 83 | below menu ~ 0px 84 | centered horizontally inside screen 1px 85 | 86 | 87 | @on desktop 88 | content: 89 | width 900px 90 | 91 | 92 | = Footer = 93 | footer: 94 | height ~ 200px 95 | below content 0px 96 | -------------------------------------------------------------------------------- /src/test/resources/specs/loginPage-withErrorMessage.spec: -------------------------------------------------------------------------------- 1 | 2 | 3 | @objects 4 | password-textfield css input[name='login.password'] 5 | login-button css .button-login 6 | error-message id login-error-message 7 | 8 | 9 | = Error message = 10 | @on * 11 | error-message: 12 | below password-textfield 5 to 15px 13 | height ~ 52px 14 | aligned vertically all password-textfield 15 | above login-button 10 to 30px 16 | 17 | 18 | @on mobile 19 | error-message: 20 | aligned vertically all login-button 21 | -------------------------------------------------------------------------------- /src/test/resources/specs/loginPage.spec: -------------------------------------------------------------------------------- 1 | @import common.spec 2 | 3 | @objects 4 | login-box id login-page 5 | login-caption css #login-page h2 6 | 7 | username-textfield css input[name='login.username'] 8 | password-textfield css input[name='login.password'] 9 | 10 | login-button css .button-login 11 | cancel-button css .button-cancel 12 | 13 | 14 | = Login box = 15 | @on * 16 | login-box: 17 | centered horizontally inside content 1px 18 | below menu 20 to 45px 19 | 20 | login-caption: 21 | height 20 to 35px 22 | text is "Login" 23 | 24 | username-textfield, password-textfield: 25 | height 25 to 35 px 26 | 27 | username-textfield: 28 | below login-caption 5 to 15px 29 | aligned vertically all password-textfield 30 | 31 | password-textfield: 32 | below username-textfield 5 to 15px 33 | aligned vertically left login-button 34 | 35 | login-button, cancel-button: 36 | height 40 to 50 px 37 | 38 | login-button: 39 | text is "Login" 40 | 41 | cancel-button: 42 | text is "Cancel" 43 | 44 | 45 | @on desktop, tablet 46 | login-box: 47 | width 400px 48 | 49 | login-caption: 50 | inside login-box ~ 40px top, ~ 20px left 51 | 52 | username-textfield, password-textfield: 53 | inside login-box ~ 20px left right 54 | 55 | login-button: 56 | below password-textfield 5 to 15px 57 | width 70 to 90 px 58 | aligned horizontally all cancel-button 59 | 60 | cancel-button: 61 | width 80 to 100 px 62 | near login-button 3 to 8px right 63 | 64 | 65 | @on mobile 66 | login-box: 67 | inside screen ~ 20px left right 68 | 69 | username-textfield, password-textfield: 70 | inside login-box 0px left right 71 | 72 | login-caption: 73 | inside login-box 0px top, 0px left 74 | 75 | login-button: 76 | inside login-box 0px left right 77 | above cancel-button 4 to 10px 78 | aligned vertically all cancel-button 79 | -------------------------------------------------------------------------------- /src/test/resources/specs/menuHighlight.spec: -------------------------------------------------------------------------------- 1 | 2 | @objects 3 | menu-item-* css #menu li a 4 | 5 | = Menu highlight = 6 | @on usual 7 | menu-item-1: 8 | color-scheme 90 to 96 % #2d6ca2, 1 to 4 % white 9 | 10 | 11 | 12 | @on hovered 13 | menu-item-1: 14 | color-scheme 90 to 96 % #205380, 1 to 4 % white 15 | -------------------------------------------------------------------------------- /src/test/resources/specs/myNotesPage.spec: -------------------------------------------------------------------------------- 1 | @import common.spec 2 | 3 | @objects 4 | caption css #my-notes-page h2 5 | 6 | note-* css .list-group a 7 | title css h4 8 | description css p 9 | 10 | button-addnote css button 11 | 12 | 13 | = Content = 14 | @on * 15 | caption: 16 | below menu 20 to 45 px 17 | inside content ~ 20px left right 18 | height 20 to 40px 19 | above note-1 10 to 20px 20 | aligned vertically all note-1 21 | 22 | 23 | note-1: 24 | above note-2 ~ 0px 25 | aligned vertically all note-2 26 | 27 | @for [ 1 - 2 ] as i 28 | note-${i}: 29 | height ~ 64px 30 | inside content ~ 20px left right 31 | 32 | note-${i}.title: 33 | inside note-${i} ~ 11 px top, ~ 16px left 34 | 35 | note-${i}.description: 36 | below note-${i}.title ~ 5 px 37 | inside note-${i} ~ 11 px bottom 38 | aligned vertically all note-${i}.title 39 | 40 | 41 | button-addnote: 42 | height ~ 45px 43 | below note-2 20 to 45 px 44 | 45 | @on desktop, tablet 46 | button-addnote: 47 | width 90 to 120px 48 | inside content ~ 20 px left 49 | aligned vertically left note-1 50 | 51 | @on mobile 52 | button-addnote: 53 | inside content ~ 20px left right 54 | -------------------------------------------------------------------------------- /src/test/resources/specs/welcomePage.spec: -------------------------------------------------------------------------------- 1 | @import common.spec 2 | 3 | @objects 4 | welcome-block css .jumbotron 5 | greeting css #welcome-page h1 6 | text-block-* css #welcome-page p 7 | login-button css #welcome-page .button-login 8 | 9 | 10 | 11 | = Content = 12 | @on * 13 | text-block-1, login-button, text-block-3: 14 | inside welcome-block ~30px left 15 | 16 | greeting: 17 | above text-block-1 10 to 50 px 18 | inside welcome-block ~ 30px left 19 | 20 | text-block-1: 21 | height > 20px 22 | above login-button 10 to 50 px 23 | 24 | login-button: 25 | height ~ 45px 26 | text is "Login" 27 | above text-block-3 10 to 50px 28 | 29 | 30 | @on desktop 31 | greeting: 32 | height ~ 69px 33 | inside welcome-block ~ 68 px top 34 | 35 | login-button: 36 | width ~ 78px 37 | 38 | 39 | @on tablet 40 | greeting: 41 | height ~ 39px 42 | inside welcome-block ~ 50 px top 43 | 44 | login-button: 45 | width ~ 78px 46 | 47 | @on mobile 48 | greeting: 49 | height ~ 78px 50 | inside welcome-block ~ 50 px top 51 | 52 | login-button: 53 | inside welcome-block ~ 30px left right 54 | --------------------------------------------------------------------------------