├── e2e ├── cypress.json ├── cypress │ └── integration │ │ └── spec.js ├── docker-compose.yml └── cy-open.yml ├── .gitignore ├── images └── cy-open.png ├── Dockerfile ├── LICENSE ├── README.md └── main.go /e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": false, 3 | "supportFile": false 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Cypress Artifacts 2 | e2e/cypress/screenshots/ 3 | e2e/cypress/videos/ 4 | e2e/cypress/fixtures/ 5 | -------------------------------------------------------------------------------- /images/cy-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahmutov/cypress-open-from-docker-compose/HEAD/images/cy-open.png -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.4-alpine3.9 2 | 3 | RUN mkdir /app 4 | COPY main.go /app/main.go 5 | WORKDIR /app 6 | 7 | ENTRYPOINT go run main.go -------------------------------------------------------------------------------- /e2e/cypress/integration/spec.js: -------------------------------------------------------------------------------- 1 | it('detects angry sentiment', () => { 2 | cy.visit('/analyze') 3 | 4 | cy.get('#feelings') 5 | .type('I REALLY need some COFFEE') 6 | cy.get('form').submit() 7 | 8 | cy.get('.results p') 9 | .should('contain', 'You are feeling: Angry') 10 | }) 11 | 12 | it('detects content sentiment 😁', () => { 13 | cy.visit('/analyze') 14 | 15 | cy.get('#feelings') 16 | .type('I think coffee in the morning is just swell!') 17 | cy.get('form').submit() 18 | 19 | cy.get('.results p') 20 | .should('contain', 'You are feeling: Content') 21 | }) -------------------------------------------------------------------------------- /e2e/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | 3 | # run Cypress tests and exit with command 4 | # docker-compose up --exit-code-from cypress 5 | services: 6 | # this is the web application we are going to test 7 | sentimentalyzer: 8 | build: ../ 9 | environment: 10 | - PORT=8123 11 | # Cypress container 12 | cypress: 13 | # the Docker image to use from https://github.com/cypress-io/cypress-docker-images 14 | image: "cypress/included:4.0.2" 15 | depends_on: 16 | - sentimentalyzer 17 | environment: 18 | # pass base url to test pointing at the web application 19 | - CYPRESS_baseUrl=http://sentimentalyzer:8123 20 | # share the current folder as volume to avoid copying 21 | working_dir: /e2e 22 | volumes: 23 | - ./:/e2e 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Michael Lynch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /e2e/cy-open.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | 3 | # run web application and open Cypress Test Runner in a Docker container 4 | # but send the X11 output to the server running on the host machine 5 | # so you can see and interact with the tests. Most services are configured 6 | # in the file docker-compose.yml, this file only overrides variables 7 | # necessary for "cypress open" to work with X11. 8 | # We need to use both file names to run: 9 | # 10 | # docker-compose -f docker-compose.yml -f cy-open.yml up --exit-code-from cypress 11 | # 12 | services: 13 | cypress: 14 | # pass custom command to start Cypress otherwise it will use the entrypoint 15 | # specified in the Cypress Docker image. 16 | # also pass "--project " so that when Cypress opens 17 | # it can find file "cypress.json" and show integration specs 18 | # https://on.cypress.io/command-line#cypress-open 19 | entrypoint: cypress open --project /e2e 20 | environment: 21 | # get the IP address of the host machine and allow X11 to accept 22 | # incoming connections from that IP address 23 | # IP=$(ipconfig getifaddr en0) 24 | # /usr/X11/bin/xhost + $IP 25 | # then pass the environment variable DISPLAY to show Cypress GUI on the host system 26 | # DISPLAY=$IP:0 27 | - DISPLAY 28 | volumes: 29 | # for Cypress to communicate with the X11 server pass this socket file 30 | # in addition to any other mapped volumes 31 | - /tmp/.X11-unix:/tmp/.X11-unix 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cypress-open-from-docker-compose 2 | 3 | Forked from [mtlynch/hello-world-cypress](https://github.com/mtlynch/hello-world-cypress) that allows to run a project and its Cypress end-to-end tests using docker-compose. The initial setup is well described in ["End-to-End Testing Web Apps: The Painless Way."](https://mtlynch.io/painless-web-app-testing/). 4 | 5 | Also read ["Run Cypress with a single Docker command"](https://www.cypress.io/blog/2019/05/02/run-cypress-with-a-single-docker-command/). 6 | 7 | ## Run headless tests 8 | 9 | [e2e/docker-compose.yml](e2e/docker-compose.yml) has all settings to start the web application and run Cypress end-to-end tests from [e2e/cypress/integration](e2e/cypress/integration) 10 | 11 | ```shell 12 | cd e2e 13 | docker-compose up --exit-code-from cypress 14 | ``` 15 | 16 | ## Run Test Runner 17 | 18 | To start Cypress Test Runner (just like `cypress open` does), you need to: 19 | 20 | - set up X11 server on the host machine, for example using [XQuartz](https://www.xquartz.org) following the [Running GUI applications using Docker for Mac](https://sourabhbajaj.com/blog/2017/02/07/gui-applications-docker-mac/) 21 | - set the `IP` variable and allow X11 server to accept incoming connections from that network address, see [e2e/cy-open.yml](e2e/cy-open.yml) for commands 22 | - set the `DISPLAY` variable and pass it to the `docker-compose` when running with both configuration files 23 | 24 | ```shell 25 | cd e2e 26 | docker-compose -f docker-compose.yml -f cy-open.yml up --exit-code-from cypress 27 | ``` 28 | 29 | You should see Cypress open and be able to run tests, change files, see tests rerun. 30 | 31 | ![Cypress open](images/cy-open.png) 32 | 33 | ## More information 34 | 35 | - [https://docs.cypress.io](https://docs.cypress.io) 36 | - [https://on.cypress.io/docker](https://on.cypress.io/docker) 37 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | "os" 9 | "unicode" 10 | ) 11 | 12 | type PageVariables struct { 13 | Sentiment string 14 | } 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = "8080" 20 | } 21 | log.Printf("Listening on port %s", port) 22 | http.HandleFunc("/", AnalyzePage) 23 | http.HandleFunc("/analyze", AnalyzePage) 24 | http.HandleFunc("/results", ResultsPage) 25 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil)) 26 | } 27 | 28 | func AnalyzePage(w http.ResponseWriter, r *http.Request) { 29 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 30 | fmt.Fprint(w, ` 31 | 32 | 33 | 34 | Sentimentalyzer 35 | 36 | 37 | 38 |
39 |

Welcome to Sentimentalyzer, the world's simplest sentiment analyzer!

40 |
41 |
42 | 43 | 44 |
45 | 46 |
47 |
48 | 49 | 50 | `) 51 | } 52 | 53 | func ResultsPage(w http.ResponseWriter, r *http.Request) { 54 | err := r.ParseForm() 55 | ResultsPageVars := PageVariables{ 56 | Sentiment: detectSentiment(r.Form.Get("feelings")), 57 | } 58 | 59 | err = template.Must(template.New("T").Parse(` 60 | 61 | 62 | 63 | Sentimentalyzer 64 | 65 | 66 | 67 |
68 |

Results

69 |

You are feeling: {{.Sentiment}}

70 |
71 | 72 | 73 | `)).Execute(w, ResultsPageVars) 74 | if err != nil { 75 | log.Print("Error generating page: ", err) 76 | } 77 | } 78 | 79 | func detectSentiment(feelings string) string { 80 | cu := countUpperCaseCharacters(feelings) 81 | cTot := countLetters(feelings) 82 | if float64(cu)/float64(cTot) > 0.5 { 83 | return "Angry" 84 | } else { 85 | return "Content" 86 | } 87 | } 88 | 89 | func countUpperCaseCharacters(str string) int { 90 | count := 0 91 | for _, c := range str { 92 | if unicode.IsUpper(c) { 93 | count++ 94 | } 95 | } 96 | return count 97 | } 98 | 99 | func countLetters(str string) int { 100 | count := 0 101 | for _, c := range str { 102 | if unicode.IsLetter(c) { 103 | count++ 104 | } 105 | } 106 | return count 107 | } 108 | --------------------------------------------------------------------------------