Skip to content

Commit 41ec069

Browse files
authored
International demographic survey (#200)
* add big demographic survey * update screenshots * update screenshots * add all fields to test * zip code test * fix education to ISCED 2011 specification + add translation for all * refactor demographics tests to utilize dynamic country data and improve structure * update GitHub Actions to use latest versions of checkout and Cypress actions * update Cypress workflow to use specific browser container image * update dependencies to latest versions for improved performance and compatibility
1 parent 93a9b1a commit 41ec069

File tree

12 files changed

+117353
-7035
lines changed

12 files changed

+117353
-7035
lines changed

.github/workflows/cypress.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ jobs:
1515

1616
timeout-minutes: 60
1717
runs-on: ${{ matrix.os }}
18+
container:
19+
image: cypress/browsers:22.12.0
20+
options: --user 1001
21+
1822
steps:
1923
- name: Checkout
20-
uses: actions/checkout@v1
24+
uses: actions/checkout@v4
2125

2226
- name: Cypress run
23-
uses: cypress-io/github-action@v4.2.0
27+
uses: cypress-io/github-action@v6
2428
with:
2529
browser: ${{ matrix.browser }}
2630
component: true

package-lock.json

Lines changed: 3191 additions & 7024 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@watts-lab/surveys",
3-
"version": "1.18.1",
3+
"version": "1.19.0",
44
"description": "",
55
"main": "dist/index.js",
66
"module": "dist/index.js",
@@ -26,25 +26,25 @@
2626
"dist"
2727
],
2828
"dependencies": {
29-
"react": "^18.2.0",
30-
"react-dom": "^18.2.0",
31-
"survey-react": "^1.9.52"
29+
"react": "^18.3.1",
30+
"react-dom": "^18.3.1",
31+
"survey-react": "^1.12.17"
3232
},
3333
"devDependencies": {
34-
"@babel/preset-react": "^7.18.6",
34+
"@babel/preset-react": "^7.26.3",
3535
"@rollup/plugin-babel": "^5.3.1",
3636
"@rollup/plugin-commonjs": "^22.0.2",
3737
"@rollup/plugin-dynamic-import-vars": "^1.4.4",
3838
"@rollup/plugin-json": "^4.1.0",
3939
"@rollup/plugin-node-resolve": "^14.1.0",
40-
"cypress": "^13.6.3",
41-
"cypress-localstorage-commands": "^2.2.1",
40+
"cypress": "^13.17.0",
41+
"cypress-localstorage-commands": "^2.2.7",
4242
"cypress-rollup-preprocessor": "^1.2.0",
4343
"glob": "^8.1.0",
44-
"rollup": "^2.79.1",
44+
"rollup": "^2.79.2",
4545
"rollup-plugin-peer-deps-external": "^2.2.4",
4646
"rollup-plugin-postcss": "^4.0.2",
4747
"rollup-plugin-terser": "^7.0.2",
48-
"vite": "^3.1.4"
48+
"vite": "^6.0.7"
4949
}
5050
}

src/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ import demographicsSha from "../surveys/demographics/sha.json";
5959
import { default as demographicsScoreFunc } from "../surveys/demographics/demographics.score.js";
6060
export const Demographics = SurveyFactory("demographics", demographicsJson, demographicsScoreFunc, demographicsSha);
6161

62+
import demographicsLongInternationalJson from "../surveys/demographicsLongInternational/demographicsLongInternational.json";
63+
import demographicsLongInternationalSha from "../surveys/demographicsLongInternational/sha.json";
64+
import { default as demographicsLongInternationalScoreFunc } from "../surveys/demographicsLongInternational/demographicsLongInternational.score.js";
65+
export const DemographicsLongInternational = SurveyFactory("demographicsLongInternational", demographicsLongInternationalJson, demographicsLongInternationalScoreFunc, demographicsLongInternationalSha);
66+
6267
import demographicsShortUSJson from "../surveys/demographicsShortUS/demographicsShortUS.json";
6368
import demographicsShortUSSha from "../surveys/demographicsShortUS/sha.json";
6469
import { default as demographicsShortUSScoreFunc } from "../surveys/demographicsShortUS/demographicsShortUS.score.js";
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Demographics Survey
2+
3+
## Survey purpose
4+
5+
Identify relatievly static attributes about an individual which are not likely to react to the stimulus in an experiment, but may be predictors of behavior.
6+
7+
The survey aims to ask questions that are appropriate to the respondent's home country, and so individuals resident in the US may (e.g.) see different survey questions than respondents from the UK.
8+
9+
### Screenshot
10+
11+
![Screenshot](screenshotGeneral.png)
12+
13+
# Question Sources
14+
15+
This survey aggregates questions from a number of sources:
16+
17+
- Impairment https://analysisfunction.civilservice.gov.uk/policy-store/impairment/
18+
19+
Using the [International Standard Classification of Education](https://en.wikipedia.org/wiki/International_Standard_Classification_of_Education)
20+
21+
Mappings from [UNESCO](http://uis.unesco.org/en/isced-mappings)
22+
23+
# Salary Range
24+
25+
The salary values and ranges were scraped on December 19th 2024 from [salaryexplorer.com](https://www.salaryexplorer.com/), and then rounded and bucketed into (If possible) 8 buckets. The values are in local currency.
26+
27+
## United Kingdom:
28+
29+
#### Education
30+
31+
Some inspiriation from https://www.lse.ac.uk/media-and-communications/assets/documents/research/preparing-for-a-digital-future/Questionnaire.pdf
32+
33+
#### Ethnicity
34+
35+
Source: https://analysisfunction.civilservice.gov.uk/policy-store/ethnicity-harmonised-standard/#questions-for-england
36+
37+
## United states
38+
39+
Questions from ANES: https://electionstudies.org/wp-content/uploads/2020/07/anes_pilot_2020ets_qnnaire.pdf
40+
41+
![Screenshot](screenshotUSA.png)
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import React from "react";
2+
import { DemographicsLongInternational } from "../../src/index";
3+
import { getContainerEl } from "cypress/react";
4+
import ReactDom from "react-dom";
5+
6+
const dummy = {
7+
set(response) {},
8+
};
9+
10+
import demographicsData from "./demographicsLongInternational.json";
11+
12+
describe("Demographics", () => {
13+
it("completes", () => {
14+
cy.spy(dummy, "set").as("callback");
15+
cy.mount(<DemographicsLongInternational onComplete={dummy.set} />);
16+
cy.viewport("macbook-11");
17+
18+
cy.get(`[data-name="birth_year"] input`).click().type("1985");
19+
20+
cy.get(`[data-name="gender"] input[value="other"]`).click({ force: true });
21+
22+
cy.get(`[data-name="gender_other"] input`).click().type("Other gender");
23+
24+
cy.get(`[data-name="marital_status"] input`).click({ force: true });
25+
26+
cy.contains("Married or Domestic Partnership").click({ force: true });
27+
28+
cy.get(`[data-name="language_primary"] input`).click({ force: true });
29+
cy.contains("French").click({ force: true });
30+
31+
cy.get(`[data-name="english_written"] input[value="4"]`).click({
32+
force: true,
33+
});
34+
35+
cy.get(`[data-name="english_spoken"] input[value="4"]`).click({
36+
force: true,
37+
});
38+
39+
cy.get(`[data-name="employment_status"] input[value="employed"]`).click({
40+
force: true,
41+
});
42+
43+
cy.get(
44+
`[data-name="employment_industry"] input[value="Agriculture, Forestry, Fishing, and Hunting"]`
45+
).click({
46+
force: true,
47+
});
48+
49+
cy.get(`[data-name="job_title"] input`).click().type("Survey Developer");
50+
51+
cy.get(`[data-name="country_reside"] input`).click({ force: true });
52+
cy.contains("United States").click({ force: true });
53+
54+
cy.screenshot("./demographicsLongInternational/screenshotGeneral", {
55+
overwrite: true,
56+
});
57+
58+
cy.get(`input[type="button"][value="Next"]`).click({ force: true });
59+
60+
cy.get(`[data-name="education_US"] input[value="Doctorate"]`).click({
61+
force: true,
62+
});
63+
64+
cy.get(`[data-name="latin_US"] input[value="Yes"]`)
65+
.next()
66+
.click({ force: true });
67+
68+
cy.get(`[data-name="zipcode_US"] input`).click().type("52066");
69+
70+
cy.get(`[data-name="race_US"] input[value="White"]`)
71+
.next()
72+
.click({ force: true });
73+
cy.get(`[data-name="race_US"] input[value="Other"]`)
74+
.next()
75+
.click({ force: true });
76+
77+
cy.get(`[data-name="income_US"] input[value="$50,000-$74,999"]`).click({
78+
force: true,
79+
});
80+
81+
cy.screenshot("./demographicsLongInternational/screenshotUSA", {
82+
overwrite: true,
83+
});
84+
85+
cy.get(`input[type="button"][value="Complete"]`).click({ force: true });
86+
87+
cy.get(".sv-body").should("not.exist");
88+
89+
cy.get("@callback").should("have.been.called");
90+
cy.get("@callback").then((spy) => {
91+
const spyCall = spy.getCall(-1).args[0];
92+
console.log(spyCall);
93+
expect(spyCall["result"]).to.be.empty;
94+
expect(spyCall.responses.birth_year).to.have.string("1985");
95+
});
96+
});
97+
98+
it("Completes Other Countries", () => {
99+
const country_list = demographicsData.pages[0].elements
100+
.find((element) => element.name === "country_reside")
101+
.choices.map((choice) => choice.value);
102+
103+
const countrySalaries = {};
104+
for (const country of country_list) {
105+
const country_code = country
106+
.toLowerCase()
107+
.replace(new RegExp(" ", "g"), "_")
108+
.replace(",", "_")
109+
.replace("(", "_")
110+
.replace(")", "_");
111+
let salaryFound = false;
112+
for (let i = 1; i < demographicsData.pages.length; i++) {
113+
const page = demographicsData.pages[i];
114+
const incomeElement = page.elements.find(
115+
(element) => element.name === `income_${country_code}`
116+
);
117+
if (incomeElement) {
118+
const salary = incomeElement.choices[0];
119+
countrySalaries[country_code] = salary;
120+
salaryFound = true;
121+
break;
122+
}
123+
}
124+
if (!salaryFound) {
125+
console.warn(`Salary data not found for country: ${country_code}`);
126+
}
127+
}
128+
129+
cy.spy(dummy, "set").as("callback");
130+
131+
country_list.slice(0, 10).forEach((country) => {
132+
const country_code = country
133+
.toLowerCase()
134+
.replace(new RegExp(" ", "g"), "_")
135+
.replace(",", "_")
136+
.replace("(", "_")
137+
.replace(")", "_");
138+
console.log(country, country_code);
139+
140+
cy.mount(
141+
<DemographicsLongInternational
142+
storageName={country_code}
143+
onComplete={dummy.set}
144+
/>
145+
);
146+
147+
// Proceed with filling out the survey
148+
cy.viewport("macbook-11");
149+
cy.get(`[data-name="birth_year"] input`).click().type("1985");
150+
cy.get(`[data-name="gender"] input[value="other"]`).click({
151+
force: true,
152+
});
153+
cy.get(`[data-name="gender_other"] input`).click().type("Other gender");
154+
cy.get(`[data-name="marital_status"] input`).click({ force: true });
155+
cy.contains("Married or Domestic Partnership").click({ force: true });
156+
cy.get(`[data-name="language_primary"] input`).click({ force: true });
157+
cy.contains("French").click({ force: true });
158+
cy.get(`[data-name="english_written"] input[value="4"]`).click({
159+
force: true,
160+
});
161+
cy.get(`[data-name="english_spoken"] input[value="4"]`).click({
162+
force: true,
163+
});
164+
cy.get(`[data-name="employment_status"] input[value="employed"]`).click({
165+
force: true,
166+
});
167+
168+
cy.get(`[data-name="country_reside"] input`).click({ force: true });
169+
cy.get(`[data-name="country_reside"]`)
170+
.contains(country)
171+
.click({ force: true });
172+
173+
cy.get(`input[type="button"][value="Next"]`).click({ force: true });
174+
cy.get(
175+
`[data-name="education_${country_code}"] input[value="Other (please specify)"]`
176+
).click({
177+
force: true,
178+
});
179+
cy.get(`[data-name="other_education_${country_code}"] input`)
180+
.click()
181+
.type("Survey Developer");
182+
cy.get(`[data-name="zipcode_${country_code}"] input`)
183+
.click()
184+
.type("82919123");
185+
cy.get(
186+
`[data-name="ethnicity_${country_code}"] input[value="Middle Eastern or North African"]`
187+
)
188+
.next()
189+
.click({ force: true });
190+
cy.get(
191+
`[data-name="income_${country_code}"] input[value="${countrySalaries[country_code]}"]`
192+
).click({
193+
force: true,
194+
});
195+
cy.get(`input[type="button"][value="Complete"]`).click({ force: true });
196+
197+
cy.wait(100);
198+
});
199+
200+
cy.get(".sv-body").should("not.exist");
201+
cy.get("@callback").should("have.been.called");
202+
cy.get("@callback").then((spy) => {
203+
const spyCall = spy.getCall(-1).args[0];
204+
console.log(spyCall);
205+
expect(spyCall["result"]).to.be.empty;
206+
expect(spyCall.responses.birth_year).to.have.string("1985");
207+
});
208+
});
209+
});

0 commit comments

Comments
 (0)