compileprofile-spacetests 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +114 -114
- package/README.md +171 -147
- package/dist/cjs/common-interfaces.d.ts +33 -1
- package/dist/cjs/gonogo.js +89 -57
- package/dist/cjs/nback.d.ts +6 -2
- package/dist/cjs/nback.js +132 -2
- package/dist/cjs/spatial-cognition.js +0 -2
- package/dist/esm/common-interfaces.d.ts +33 -1
- package/dist/esm/gonogo.js +89 -57
- package/dist/esm/nback.d.ts +6 -2
- package/dist/esm/nback.js +128 -2
- package/dist/esm/spatial-cognition.js +0 -2
- package/example-data/emotions.json +807 -807
- package/example-data/gonogo.json +5392 -5392
- package/example-data/nback.json +892 -892
- package/example-data/participant.json +6 -6
- package/example-data/spatial-cognition.json +462 -462
- package/jest.config.js +13 -13
- package/original/emotion-recognition.R +39 -39
- package/original/gonogo.R +32 -32
- package/package.json +40 -40
- package/src/__tests__/integration/browserInfo.test.ts +16 -16
- package/src/__tests__/integration/emotions.test.ts +172 -172
- package/src/__tests__/integration/gonogo.test.ts +293 -183
- package/src/__tests__/integration/nback-versions.test.ts +182 -0
- package/src/__tests__/integration/nback.test.ts +148 -148
- package/src/__tests__/integration/spatial-cognition.test.ts +171 -171
- package/src/__tests__/test-utils/testData.ts +79 -79
- package/src/common-interfaces.ts +124 -78
- package/src/emotions.ts +98 -98
- package/src/getters.ts +21 -21
- package/src/gonogo.ts +149 -127
- package/src/index.ts +39 -39
- package/src/nback.ts +182 -61
- package/src/spatial-cognition.ts +110 -112
- package/tsconfig.cjs.json +12 -12
- package/tsconfig.esm.json +14 -14
package/jest.config.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
testEnvironment: 'node',
|
|
4
|
-
roots: ['<rootDir>/src'],
|
|
5
|
-
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
|
|
6
|
-
transform: {
|
|
7
|
-
'^.+\\.ts$': 'ts-jest'
|
|
8
|
-
},
|
|
9
|
-
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
|
|
10
|
-
// ignore test-utils folder
|
|
11
|
-
testPathIgnorePatterns: ['<rootDir>/src/__tests__/test-utils/'],
|
|
12
|
-
setupFilesAfterEnv: ['<rootDir>/src/__tests__/test-utils/testData.ts'],
|
|
13
|
-
moduleDirectories: ['node_modules', 'example-data']
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
roots: ['<rootDir>/src'],
|
|
5
|
+
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
|
|
6
|
+
transform: {
|
|
7
|
+
'^.+\\.ts$': 'ts-jest'
|
|
8
|
+
},
|
|
9
|
+
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
|
|
10
|
+
// ignore test-utils folder
|
|
11
|
+
testPathIgnorePatterns: ['<rootDir>/src/__tests__/test-utils/'],
|
|
12
|
+
setupFilesAfterEnv: ['<rootDir>/src/__tests__/test-utils/testData.ts'],
|
|
13
|
+
moduleDirectories: ['node_modules', 'example-data']
|
|
14
14
|
};
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
emotion_create_trial_table <- function(txt) {
|
|
2
|
-
emotion_values <- c(`0` = "neutral", `1` = "sad", `2` = "happy",
|
|
3
|
-
`3` = "surprised", `4` = "angry")
|
|
4
|
-
df <- results_to_df(txt) %>%
|
|
5
|
-
emotions_extract_emotion() %>%
|
|
6
|
-
filter(!is.na(response), !is.na(emotion)) %>%
|
|
7
|
-
mutate(emotion_response = emotion_values[response + 1],
|
|
8
|
-
correct = emotion == emotion_response,
|
|
9
|
-
index = 1:n(),
|
|
10
|
-
block = c(rep("regular", 15), rep("quick", 15), rep("rotated", 15))) %>%
|
|
11
|
-
select(emotion, emotion_response, correct, index, block, image, rt)
|
|
12
|
-
return(df)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
emotion_analyze_performance <- function(df) {
|
|
16
|
-
df_out <- df %>%
|
|
17
|
-
group_by(block) %>%
|
|
18
|
-
summarise(correct = sum(correct) / n(),
|
|
19
|
-
mean_rt = mean(rt),
|
|
20
|
-
.groups = "drop") %>%
|
|
21
|
-
rowwise() %>%
|
|
22
|
-
# We are making the performance metric to be the inverse of the correct
|
|
23
|
-
# so that lower values are always better (mean RT is better lower)
|
|
24
|
-
mutate(performance = ifelse(block == "quick", 1-correct, mean_rt/correct)) %>%
|
|
25
|
-
ungroup()
|
|
26
|
-
return(df_out)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
emotions_extract_emotion <- function(df) {
|
|
30
|
-
URL <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/"
|
|
31
|
-
df <- df %>%
|
|
32
|
-
mutate(
|
|
33
|
-
image = emotion,
|
|
34
|
-
emotion = gsub(URL, "", emotion),
|
|
35
|
-
emotion = gsub(".png", "", emotion),
|
|
36
|
-
emotion = gsub("_\\d+", "", emotion)
|
|
37
|
-
)
|
|
38
|
-
return(df)
|
|
39
|
-
}
|
|
1
|
+
emotion_create_trial_table <- function(txt) {
|
|
2
|
+
emotion_values <- c(`0` = "neutral", `1` = "sad", `2` = "happy",
|
|
3
|
+
`3` = "surprised", `4` = "angry")
|
|
4
|
+
df <- results_to_df(txt) %>%
|
|
5
|
+
emotions_extract_emotion() %>%
|
|
6
|
+
filter(!is.na(response), !is.na(emotion)) %>%
|
|
7
|
+
mutate(emotion_response = emotion_values[response + 1],
|
|
8
|
+
correct = emotion == emotion_response,
|
|
9
|
+
index = 1:n(),
|
|
10
|
+
block = c(rep("regular", 15), rep("quick", 15), rep("rotated", 15))) %>%
|
|
11
|
+
select(emotion, emotion_response, correct, index, block, image, rt)
|
|
12
|
+
return(df)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
emotion_analyze_performance <- function(df) {
|
|
16
|
+
df_out <- df %>%
|
|
17
|
+
group_by(block) %>%
|
|
18
|
+
summarise(correct = sum(correct) / n(),
|
|
19
|
+
mean_rt = mean(rt),
|
|
20
|
+
.groups = "drop") %>%
|
|
21
|
+
rowwise() %>%
|
|
22
|
+
# We are making the performance metric to be the inverse of the correct
|
|
23
|
+
# so that lower values are always better (mean RT is better lower)
|
|
24
|
+
mutate(performance = ifelse(block == "quick", 1-correct, mean_rt/correct)) %>%
|
|
25
|
+
ungroup()
|
|
26
|
+
return(df_out)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
emotions_extract_emotion <- function(df) {
|
|
30
|
+
URL <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/"
|
|
31
|
+
df <- df %>%
|
|
32
|
+
mutate(
|
|
33
|
+
image = emotion,
|
|
34
|
+
emotion = gsub(URL, "", emotion),
|
|
35
|
+
emotion = gsub(".png", "", emotion),
|
|
36
|
+
emotion = gsub("_\\d+", "", emotion)
|
|
37
|
+
)
|
|
38
|
+
return(df)
|
|
39
|
+
}
|
package/original/gonogo.R
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
gonogo_create_trial_table <- function(txt) {
|
|
2
|
-
arr <- fromJSON(txt)
|
|
3
|
-
df <- as.data.frame(fromJSON(arr[[1]]))
|
|
4
|
-
GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
5
|
-
df <- filter(df, !is.na(image))
|
|
6
|
-
df <- select(df, trial_index, time_elapsed, rt,
|
|
7
|
-
response, block_number, image)
|
|
8
|
-
df$image <- gsub(GONOGO_IMAGE_PATH, "", df$image)
|
|
9
|
-
df$image <- gsub(".png", "", df$image)
|
|
10
|
-
df <- df %>%
|
|
11
|
-
mutate(
|
|
12
|
-
should_go = case_when(
|
|
13
|
-
block_number == 1 & grepl("astronaut_trans_1", image) ~ TRUE,
|
|
14
|
-
block_number == 2 & grepl("alien_trans_1", image) ~ TRUE,
|
|
15
|
-
block_number == 3 & grepl("rocket_trans_1", image) ~ TRUE,
|
|
16
|
-
block_number == 4 & !grepl("rocket_trans_1", image) ~ TRUE,
|
|
17
|
-
TRUE ~ FALSE),
|
|
18
|
-
did_go = !is.na(response),
|
|
19
|
-
correct = should_go == did_go
|
|
20
|
-
)
|
|
21
|
-
return(df)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
gonogo_analyze_performance <- function(df) {
|
|
25
|
-
df_out <- df %>%
|
|
26
|
-
group_by(block = block_number) %>%
|
|
27
|
-
summarise(correct = sum(correct) / n(),
|
|
28
|
-
mean_rt = mean(rt[should_go], na.rm = TRUE),
|
|
29
|
-
performance = mean_rt / correct,
|
|
30
|
-
.groups = "drop")
|
|
31
|
-
return(df_out)
|
|
32
|
-
}
|
|
1
|
+
gonogo_create_trial_table <- function(txt) {
|
|
2
|
+
arr <- fromJSON(txt)
|
|
3
|
+
df <- as.data.frame(fromJSON(arr[[1]]))
|
|
4
|
+
GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
5
|
+
df <- filter(df, !is.na(image))
|
|
6
|
+
df <- select(df, trial_index, time_elapsed, rt,
|
|
7
|
+
response, block_number, image)
|
|
8
|
+
df$image <- gsub(GONOGO_IMAGE_PATH, "", df$image)
|
|
9
|
+
df$image <- gsub(".png", "", df$image)
|
|
10
|
+
df <- df %>%
|
|
11
|
+
mutate(
|
|
12
|
+
should_go = case_when(
|
|
13
|
+
block_number == 1 & grepl("astronaut_trans_1", image) ~ TRUE,
|
|
14
|
+
block_number == 2 & grepl("alien_trans_1", image) ~ TRUE,
|
|
15
|
+
block_number == 3 & grepl("rocket_trans_1", image) ~ TRUE,
|
|
16
|
+
block_number == 4 & !grepl("rocket_trans_1", image) ~ TRUE,
|
|
17
|
+
TRUE ~ FALSE),
|
|
18
|
+
did_go = !is.na(response),
|
|
19
|
+
correct = should_go == did_go
|
|
20
|
+
)
|
|
21
|
+
return(df)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
gonogo_analyze_performance <- function(df) {
|
|
25
|
+
df_out <- df %>%
|
|
26
|
+
group_by(block = block_number) %>%
|
|
27
|
+
summarise(correct = sum(correct) / n(),
|
|
28
|
+
mean_rt = mean(rt[should_go], na.rm = TRUE),
|
|
29
|
+
performance = mean_rt / correct,
|
|
30
|
+
.groups = "drop")
|
|
31
|
+
return(df_out)
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "compileprofile-spacetests",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A package for evaluating cognitive test results from ",
|
|
5
|
-
"main": "dist/cjs/index.js",
|
|
6
|
-
"module": "dist/esm/index.js",
|
|
7
|
-
"types": "dist/cjs/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": "./dist/esm/index.js",
|
|
11
|
-
"require": "./dist/cjs/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "npm run build:csj && npm run build:esm",
|
|
16
|
-
"build:csj": "tsc --project tsconfig.cjs.json",
|
|
17
|
-
"build:esm": "tsc --project tsconfig.esm.json",
|
|
18
|
-
"test": "jest",
|
|
19
|
-
"output gonogo": "node dist/index.js",
|
|
20
|
-
"prepare": "npm run build"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"cognitive",
|
|
24
|
-
"testing",
|
|
25
|
-
"memory",
|
|
26
|
-
"evaluation"
|
|
27
|
-
],
|
|
28
|
-
"author": "",
|
|
29
|
-
"license": "MIT",
|
|
30
|
-
"devDependencies": {
|
|
31
|
-
"@types/jest": "^29.5.12",
|
|
32
|
-
"@types/node": "^20.11.24",
|
|
33
|
-
"jest": "^29.7.0",
|
|
34
|
-
"ts-jest": "^29.1.2",
|
|
35
|
-
"typescript": "^5.3.3"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"mathjs": "^14.4.0"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "compileprofile-spacetests",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "A package for evaluating cognitive test results from ",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/cjs/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/esm/index.js",
|
|
11
|
+
"require": "./dist/cjs/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "npm run build:csj && npm run build:esm",
|
|
16
|
+
"build:csj": "tsc --project tsconfig.cjs.json",
|
|
17
|
+
"build:esm": "tsc --project tsconfig.esm.json",
|
|
18
|
+
"test": "jest",
|
|
19
|
+
"output gonogo": "node dist/index.js",
|
|
20
|
+
"prepare": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"cognitive",
|
|
24
|
+
"testing",
|
|
25
|
+
"memory",
|
|
26
|
+
"evaluation"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/jest": "^29.5.12",
|
|
32
|
+
"@types/node": "^20.11.24",
|
|
33
|
+
"jest": "^29.7.0",
|
|
34
|
+
"ts-jest": "^29.1.2",
|
|
35
|
+
"typescript": "^5.3.3"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"mathjs": "^14.4.0"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { getBrowserInformation } from '../../getters';
|
|
2
|
-
import { loadTestData } from '../test-utils/testData';
|
|
3
|
-
|
|
4
|
-
describe('Browser Information Integration Tests', () => {
|
|
5
|
-
const testData = loadTestData('nback');
|
|
6
|
-
|
|
7
|
-
// Test with spatial cognition data
|
|
8
|
-
it('should extract browser info from spatial cognition data', () => {
|
|
9
|
-
const browserInfo = getBrowserInformation(testData.nback);
|
|
10
|
-
// expect browserInfo to be an object with the following properties
|
|
11
|
-
expect(browserInfo).toMatchObject({
|
|
12
|
-
browser: expect.any(String),
|
|
13
|
-
os: expect.any(String),
|
|
14
|
-
mobile: expect.any(Boolean)
|
|
15
|
-
});
|
|
16
|
-
});
|
|
1
|
+
import { getBrowserInformation } from '../../getters';
|
|
2
|
+
import { loadTestData } from '../test-utils/testData';
|
|
3
|
+
|
|
4
|
+
describe('Browser Information Integration Tests', () => {
|
|
5
|
+
const testData = loadTestData('nback');
|
|
6
|
+
|
|
7
|
+
// Test with spatial cognition data
|
|
8
|
+
it('should extract browser info from spatial cognition data', () => {
|
|
9
|
+
const browserInfo = getBrowserInformation(testData.nback);
|
|
10
|
+
// expect browserInfo to be an object with the following properties
|
|
11
|
+
expect(browserInfo).toMatchObject({
|
|
12
|
+
browser: expect.any(String),
|
|
13
|
+
os: expect.any(String),
|
|
14
|
+
mobile: expect.any(Boolean)
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
17
|
});
|
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
import { emotion_extract_trials, emotion_results,
|
|
2
|
-
emotion_calculate_results } from '../../emotions';
|
|
3
|
-
import { loadTestData } from '../test-utils/testData';
|
|
4
|
-
|
|
5
|
-
describe('Emotions test module', () => {
|
|
6
|
-
const emotionsData = loadTestData('emotions').emotions;
|
|
7
|
-
|
|
8
|
-
// Comprehensive mock data for predictable testing
|
|
9
|
-
const mockEmotionsData = [
|
|
10
|
-
{
|
|
11
|
-
"index": 1,
|
|
12
|
-
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/surprised_3.png",
|
|
13
|
-
"rt": 1000,
|
|
14
|
-
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/surprised_3.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
15
|
-
"response": 3,
|
|
16
|
-
"trial_type": "html-button-response",
|
|
17
|
-
"trial_index": 9,
|
|
18
|
-
"plugin_version": "2.0.0",
|
|
19
|
-
"time_elapsed": 45416,
|
|
20
|
-
"attempted": false
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"index": 2,
|
|
24
|
-
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_1.png",
|
|
25
|
-
"rt": 1000,
|
|
26
|
-
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_1.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
27
|
-
"response": 1,
|
|
28
|
-
"trial_type": "html-button-response",
|
|
29
|
-
"trial_index": 10,
|
|
30
|
-
"plugin_version": "2.0.0",
|
|
31
|
-
"time_elapsed": 47656,
|
|
32
|
-
"attempted": false
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"index": 3,
|
|
36
|
-
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/angry_1.png",
|
|
37
|
-
"rt": 2000,
|
|
38
|
-
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/angry_1.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
39
|
-
"response": 3,
|
|
40
|
-
"trial_type": "html-button-response",
|
|
41
|
-
"trial_index": 11,
|
|
42
|
-
"plugin_version": "2.0.0",
|
|
43
|
-
"time_elapsed": 49698,
|
|
44
|
-
"attempted": false
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"index": 4,
|
|
48
|
-
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_3.png",
|
|
49
|
-
"rt": 1000,
|
|
50
|
-
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_3.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
51
|
-
"response": 1,
|
|
52
|
-
"trial_type": "html-button-response",
|
|
53
|
-
"trial_index": 12,
|
|
54
|
-
"plugin_version": "2.0.0",
|
|
55
|
-
"time_elapsed": 52944,
|
|
56
|
-
"attempted": false
|
|
57
|
-
},
|
|
58
|
-
// Non-emotion data that should be filtered out
|
|
59
|
-
{ trial_type: 'browser-check', browser: 'safari' }
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
describe('emotion_extract_trials', () => {
|
|
63
|
-
it('should extract trials from raw data', () => {
|
|
64
|
-
const trials = emotion_extract_trials(emotionsData);
|
|
65
|
-
expect(trials.length).toBeLessThan(emotionsData.length);
|
|
66
|
-
trials.forEach(trial => {
|
|
67
|
-
expect(trial).toHaveProperty('rt');
|
|
68
|
-
expect(trial).toHaveProperty('emotion');
|
|
69
|
-
expect(trial).toHaveProperty('emotion_response');
|
|
70
|
-
expect(trial).toHaveProperty('correct');
|
|
71
|
-
// property correct should be boolean
|
|
72
|
-
expect(typeof trial.correct).toBe('boolean');
|
|
73
|
-
expect(trial).toHaveProperty('image_number');
|
|
74
|
-
expect(typeof trial.emotion).toBe('string');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('should handle empty data array', () => {
|
|
79
|
-
const trials = emotion_extract_trials([]);
|
|
80
|
-
expect(trials).toEqual([]);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should extract mock data correctly', () => {
|
|
84
|
-
const trials = emotion_extract_trials(mockEmotionsData);
|
|
85
|
-
expect(trials.length).toBe(4); // Only trials with valid emotion, rt, and response
|
|
86
|
-
|
|
87
|
-
// Check emotion extraction and response mapping
|
|
88
|
-
expect(trials[0].emotion).toBe('surprised');
|
|
89
|
-
expect(trials[0].image_number).toBe('3');
|
|
90
|
-
expect(trials[0].emotion_response).toBe('surprised');
|
|
91
|
-
expect(trials[0].correct).toBe(true);
|
|
92
|
-
|
|
93
|
-
expect(trials[1].emotion).toBe('sad');
|
|
94
|
-
expect(trials[1].emotion_response).toBe('sad');
|
|
95
|
-
expect(trials[1].correct).toBe(true);
|
|
96
|
-
|
|
97
|
-
expect(trials[2].emotion).toBe('angry');
|
|
98
|
-
expect(trials[2].emotion_response).toBe('surprised');
|
|
99
|
-
expect(trials[2].correct).toBe(false);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('emotion_results', () => {
|
|
104
|
-
it('should calculate correct averages', () => {
|
|
105
|
-
// Create sample trial data
|
|
106
|
-
const sampleTrials = [
|
|
107
|
-
{ rt: 600, correct: true, emotion: 'happy', emotion_response: 'happy' },
|
|
108
|
-
{ rt: 1000, correct: true, emotion: 'sad', emotion_response: 'sad' },
|
|
109
|
-
{ rt: 800, correct: false, emotion: 'angry', emotion_response: 'happy' },
|
|
110
|
-
{ rt: 400, correct: false, emotion: 'sad', emotion_response: 'happy' },
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
const results = emotion_results(sampleTrials);
|
|
114
|
-
|
|
115
|
-
expect(results).toHaveProperty('common');
|
|
116
|
-
expect(results.common.n_trials).toBe(4);
|
|
117
|
-
expect(results.common.avg_rt_total).toBe(700); // (600 + 1000 + 800 + 400) / 4
|
|
118
|
-
expect(results.common.n_correct_trials / results.common.n_trials).toBe(2/4); // (1 + 1 + 0 + 0) / 4
|
|
119
|
-
expect(results.common.performance_score).toBeGreaterThanOrEqual(0);
|
|
120
|
-
expect(results.common.performance_score).toBeLessThanOrEqual(100);
|
|
121
|
-
expect(results).toHaveProperty('special');
|
|
122
|
-
expect(results.special).toHaveProperty('by_emotion');
|
|
123
|
-
expect(results.special).toHaveProperty('confusion_matrix');
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should handle empty trials array', () => {
|
|
127
|
-
// When given an empty array, it should handle it gracefully
|
|
128
|
-
expect(() => emotion_results([])).toThrow();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should calculate mock data results correctly', () => {
|
|
132
|
-
const mockTrials = emotion_extract_trials(mockEmotionsData);
|
|
133
|
-
const mockResults = emotion_results(mockTrials);
|
|
134
|
-
|
|
135
|
-
// Expected: 5 trials total, 4 correct, 1 incorrect, 0 missing (missing was filtered out)
|
|
136
|
-
expect(mockResults.common.n_trials).toBe(4);
|
|
137
|
-
expect(mockResults.common.n_correct_trials).toBe(3);
|
|
138
|
-
expect(mockResults.common.n_incorrect_trials).toBe(1);
|
|
139
|
-
|
|
140
|
-
expect(mockResults.common.avg_rt_total).toBe(1250);
|
|
141
|
-
expect(mockResults.common.avg_rt_correct).toBe(1000);
|
|
142
|
-
expect(mockResults.common.avg_rt_incorrect).toBe(2000);
|
|
143
|
-
|
|
144
|
-
// Performance score calculation using RT/(accuracy^5)
|
|
145
|
-
expect(mockResults.common.performance_score).toBeGreaterThan(0);
|
|
146
|
-
expect(mockResults.common.performance_score).toBeLessThanOrEqual(100);
|
|
147
|
-
|
|
148
|
-
// Check special results structure
|
|
149
|
-
expect(mockResults.special.by_emotion).toHaveLength(5); // neutral, sad, happy, surprised, angry
|
|
150
|
-
expect(mockResults.special.confusion_matrix).toHaveProperty('happy');
|
|
151
|
-
expect(mockResults.special.confusion_matrix).toHaveProperty('sad');
|
|
152
|
-
expect(mockResults.special.confusion_matrix).toHaveProperty('angry');
|
|
153
|
-
expect(mockResults.special.confusion_matrix).toHaveProperty('neutral');
|
|
154
|
-
expect(mockResults.special.confusion_matrix).toHaveProperty('surprised');
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe('emotion_calculate_results', () => {
|
|
159
|
-
it('should process raw data and return valid results', () => {
|
|
160
|
-
const results = emotion_calculate_results(emotionsData);
|
|
161
|
-
console.log(results);
|
|
162
|
-
expect(results).toHaveProperty('common');
|
|
163
|
-
expect(results).toHaveProperty('special');
|
|
164
|
-
expect(results.common).toHaveProperty('n_trials');
|
|
165
|
-
expect(results.common).toHaveProperty('n_correct_trials');
|
|
166
|
-
expect(results.common).toHaveProperty('avg_rt_total');
|
|
167
|
-
expect(results.common).toHaveProperty('performance_score');
|
|
168
|
-
|
|
169
|
-
expect(results.common.performance_score).toBeGreaterThan(0);
|
|
170
|
-
expect(results.common.performance_score).toBeLessThanOrEqual(100);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
1
|
+
import { emotion_extract_trials, emotion_results,
|
|
2
|
+
emotion_calculate_results } from '../../emotions';
|
|
3
|
+
import { loadTestData } from '../test-utils/testData';
|
|
4
|
+
|
|
5
|
+
describe('Emotions test module', () => {
|
|
6
|
+
const emotionsData = loadTestData('emotions').emotions;
|
|
7
|
+
|
|
8
|
+
// Comprehensive mock data for predictable testing
|
|
9
|
+
const mockEmotionsData = [
|
|
10
|
+
{
|
|
11
|
+
"index": 1,
|
|
12
|
+
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/surprised_3.png",
|
|
13
|
+
"rt": 1000,
|
|
14
|
+
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/surprised_3.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
15
|
+
"response": 3,
|
|
16
|
+
"trial_type": "html-button-response",
|
|
17
|
+
"trial_index": 9,
|
|
18
|
+
"plugin_version": "2.0.0",
|
|
19
|
+
"time_elapsed": 45416,
|
|
20
|
+
"attempted": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"index": 2,
|
|
24
|
+
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_1.png",
|
|
25
|
+
"rt": 1000,
|
|
26
|
+
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_1.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
27
|
+
"response": 1,
|
|
28
|
+
"trial_type": "html-button-response",
|
|
29
|
+
"trial_index": 10,
|
|
30
|
+
"plugin_version": "2.0.0",
|
|
31
|
+
"time_elapsed": 47656,
|
|
32
|
+
"attempted": false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"index": 3,
|
|
36
|
+
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/angry_1.png",
|
|
37
|
+
"rt": 2000,
|
|
38
|
+
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/angry_1.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
39
|
+
"response": 3,
|
|
40
|
+
"trial_type": "html-button-response",
|
|
41
|
+
"trial_index": 11,
|
|
42
|
+
"plugin_version": "2.0.0",
|
|
43
|
+
"time_elapsed": 49698,
|
|
44
|
+
"attempted": false
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"index": 4,
|
|
48
|
+
"emotion": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_3.png",
|
|
49
|
+
"rt": 1000,
|
|
50
|
+
"stimulus": "<img src=\"https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/emotions//final/sad_3.png\" class=\"max-w-none rotate_0\" width=\"512\" height=\"512\" alt=\"Mapa\">",
|
|
51
|
+
"response": 1,
|
|
52
|
+
"trial_type": "html-button-response",
|
|
53
|
+
"trial_index": 12,
|
|
54
|
+
"plugin_version": "2.0.0",
|
|
55
|
+
"time_elapsed": 52944,
|
|
56
|
+
"attempted": false
|
|
57
|
+
},
|
|
58
|
+
// Non-emotion data that should be filtered out
|
|
59
|
+
{ trial_type: 'browser-check', browser: 'safari' }
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
describe('emotion_extract_trials', () => {
|
|
63
|
+
it('should extract trials from raw data', () => {
|
|
64
|
+
const trials = emotion_extract_trials(emotionsData);
|
|
65
|
+
expect(trials.length).toBeLessThan(emotionsData.length);
|
|
66
|
+
trials.forEach(trial => {
|
|
67
|
+
expect(trial).toHaveProperty('rt');
|
|
68
|
+
expect(trial).toHaveProperty('emotion');
|
|
69
|
+
expect(trial).toHaveProperty('emotion_response');
|
|
70
|
+
expect(trial).toHaveProperty('correct');
|
|
71
|
+
// property correct should be boolean
|
|
72
|
+
expect(typeof trial.correct).toBe('boolean');
|
|
73
|
+
expect(trial).toHaveProperty('image_number');
|
|
74
|
+
expect(typeof trial.emotion).toBe('string');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should handle empty data array', () => {
|
|
79
|
+
const trials = emotion_extract_trials([]);
|
|
80
|
+
expect(trials).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should extract mock data correctly', () => {
|
|
84
|
+
const trials = emotion_extract_trials(mockEmotionsData);
|
|
85
|
+
expect(trials.length).toBe(4); // Only trials with valid emotion, rt, and response
|
|
86
|
+
|
|
87
|
+
// Check emotion extraction and response mapping
|
|
88
|
+
expect(trials[0].emotion).toBe('surprised');
|
|
89
|
+
expect(trials[0].image_number).toBe('3');
|
|
90
|
+
expect(trials[0].emotion_response).toBe('surprised');
|
|
91
|
+
expect(trials[0].correct).toBe(true);
|
|
92
|
+
|
|
93
|
+
expect(trials[1].emotion).toBe('sad');
|
|
94
|
+
expect(trials[1].emotion_response).toBe('sad');
|
|
95
|
+
expect(trials[1].correct).toBe(true);
|
|
96
|
+
|
|
97
|
+
expect(trials[2].emotion).toBe('angry');
|
|
98
|
+
expect(trials[2].emotion_response).toBe('surprised');
|
|
99
|
+
expect(trials[2].correct).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('emotion_results', () => {
|
|
104
|
+
it('should calculate correct averages', () => {
|
|
105
|
+
// Create sample trial data
|
|
106
|
+
const sampleTrials = [
|
|
107
|
+
{ rt: 600, correct: true, emotion: 'happy', emotion_response: 'happy' },
|
|
108
|
+
{ rt: 1000, correct: true, emotion: 'sad', emotion_response: 'sad' },
|
|
109
|
+
{ rt: 800, correct: false, emotion: 'angry', emotion_response: 'happy' },
|
|
110
|
+
{ rt: 400, correct: false, emotion: 'sad', emotion_response: 'happy' },
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
const results = emotion_results(sampleTrials);
|
|
114
|
+
|
|
115
|
+
expect(results).toHaveProperty('common');
|
|
116
|
+
expect(results.common.n_trials).toBe(4);
|
|
117
|
+
expect(results.common.avg_rt_total).toBe(700); // (600 + 1000 + 800 + 400) / 4
|
|
118
|
+
expect(results.common.n_correct_trials / results.common.n_trials).toBe(2/4); // (1 + 1 + 0 + 0) / 4
|
|
119
|
+
expect(results.common.performance_score).toBeGreaterThanOrEqual(0);
|
|
120
|
+
expect(results.common.performance_score).toBeLessThanOrEqual(100);
|
|
121
|
+
expect(results).toHaveProperty('special');
|
|
122
|
+
expect(results.special).toHaveProperty('by_emotion');
|
|
123
|
+
expect(results.special).toHaveProperty('confusion_matrix');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should handle empty trials array', () => {
|
|
127
|
+
// When given an empty array, it should handle it gracefully
|
|
128
|
+
expect(() => emotion_results([])).toThrow();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should calculate mock data results correctly', () => {
|
|
132
|
+
const mockTrials = emotion_extract_trials(mockEmotionsData);
|
|
133
|
+
const mockResults = emotion_results(mockTrials);
|
|
134
|
+
|
|
135
|
+
// Expected: 5 trials total, 4 correct, 1 incorrect, 0 missing (missing was filtered out)
|
|
136
|
+
expect(mockResults.common.n_trials).toBe(4);
|
|
137
|
+
expect(mockResults.common.n_correct_trials).toBe(3);
|
|
138
|
+
expect(mockResults.common.n_incorrect_trials).toBe(1);
|
|
139
|
+
|
|
140
|
+
expect(mockResults.common.avg_rt_total).toBe(1250);
|
|
141
|
+
expect(mockResults.common.avg_rt_correct).toBe(1000);
|
|
142
|
+
expect(mockResults.common.avg_rt_incorrect).toBe(2000);
|
|
143
|
+
|
|
144
|
+
// Performance score calculation using RT/(accuracy^5)
|
|
145
|
+
expect(mockResults.common.performance_score).toBeGreaterThan(0);
|
|
146
|
+
expect(mockResults.common.performance_score).toBeLessThanOrEqual(100);
|
|
147
|
+
|
|
148
|
+
// Check special results structure
|
|
149
|
+
expect(mockResults.special.by_emotion).toHaveLength(5); // neutral, sad, happy, surprised, angry
|
|
150
|
+
expect(mockResults.special.confusion_matrix).toHaveProperty('happy');
|
|
151
|
+
expect(mockResults.special.confusion_matrix).toHaveProperty('sad');
|
|
152
|
+
expect(mockResults.special.confusion_matrix).toHaveProperty('angry');
|
|
153
|
+
expect(mockResults.special.confusion_matrix).toHaveProperty('neutral');
|
|
154
|
+
expect(mockResults.special.confusion_matrix).toHaveProperty('surprised');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('emotion_calculate_results', () => {
|
|
159
|
+
it('should process raw data and return valid results', () => {
|
|
160
|
+
const results = emotion_calculate_results(emotionsData);
|
|
161
|
+
console.log(results);
|
|
162
|
+
expect(results).toHaveProperty('common');
|
|
163
|
+
expect(results).toHaveProperty('special');
|
|
164
|
+
expect(results.common).toHaveProperty('n_trials');
|
|
165
|
+
expect(results.common).toHaveProperty('n_correct_trials');
|
|
166
|
+
expect(results.common).toHaveProperty('avg_rt_total');
|
|
167
|
+
expect(results.common).toHaveProperty('performance_score');
|
|
168
|
+
|
|
169
|
+
expect(results.common.performance_score).toBeGreaterThan(0);
|
|
170
|
+
expect(results.common.performance_score).toBeLessThanOrEqual(100);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
173
|
});
|