DEV Community

Nico Varga
Nico Varga

Posted on

Building an MBTI Cognitive Functions Test in JavaScript: Data Model and Scoring

Title card: building an MBTI cognitive functions test in JavaScript, data model and scoring

An mbti cognitive functions test is one of those projects that looks like a form full of radio buttons until you sit down to write the scoring. This post builds the data layer for one in plain JavaScript: a model of the eight functions, rule-based derivation of each type's four-function stack, a scorer that ranks all sixteen types, tie handling, and unit tests. One caveat shapes everything below: a self-report measures how strongly you agree with statements written from a theory. It does not observe your functions. With that settled, an mbti cognitive functions test is a genuinely fun engineering problem.

What an MBTI cognitive functions test actually measures

Start with vocabulary. Jung described sensing, intuition, thinking and feeling, and as MBF on type dynamics puts it, "Jung called the processes functions." Attach an attitude — extraverted or introverted — and you get eight functions: Se, Si, Ne, Ni, Te, Ti, Fe and Fi. Type dynamics arranges four per type as Dominant, Auxiliary, Tertiary and Inferior. The fourth letter names the process you extravert: J extraverts judging (T or F), P extraverts perceiving (S or N). Extraverts use the dominant in the outer world; introverts show the auxiliary outwardly. Every mbti cognitive functions test is downstream of those rules.

Jung also wrote that "all the basic psychological functions seldom or never have the same strength or grade of development in one and the same individual" — as a rule, one predominates (Jung, Psychological Types, Ch. X). Hence stack-position scoring in this mbti cognitive functions test. But be precise about what any mbti functions test does: it asks how much you recognize yourself in descriptions of Ni or Se. A cognitive functions mbti test scores agreement with a taxonomy, not cognition itself, and an mbti cognitive functions test that claims more in its copy is overclaiming.

Data model for an mbti cognitive functions test

Three pieces carry the whole mbti cognitive functions test: the function list, statements that each target one function, and a scorer producing comparable numbers. Here is the skeleton I would start any jungian cognitive functions test with. Every later piece of the mbti cognitive functions test reads from it:

// Eight Jungian functions: a process (S, N, T, F) plus an attitude (e or i)
const FUNCTIONS = ['Se', 'Si', 'Ne', 'Ni', 'Te', 'Ti', 'Fe', 'Fi'];

// Each item measures one function on a 1-5 scale; 4 items per function, 32 total
const items = [
  { id: 1, fn: 'Ni', text: 'I often know where something is heading before I can explain why.' },
  { id: 2, fn: 'Se', text: 'I notice small changes in a room as soon as I walk in.' },
  // ...
];

function scoreFunctions(answers) {            // answers: { [itemId]: 1..5 }
  const totals = Object.fromEntries(FUNCTIONS.map(f => [f, 0]));
  const counts = Object.fromEntries(FUNCTIONS.map(f => [f, 0]));
  for (const item of items) {
    const a = answers[item.id];
    if (a == null) continue;                  // skipped items don't count
    totals[item.fn] += a - 3;                 // center the scale: -2..+2
    counts[item.fn] += 1;
  }
  return Object.fromEntries(FUNCTIONS.map(f =>
    [f, counts[f] ? totals[f] / (2 * counts[f]) : null]));  // -1..+1, or null
}
Enter fullscreen mode Exit fullscreen mode

Answers are centered on 3, so disagreement pushes a function negative, and dividing by twice the number of answered items clamps each score into -1..+1. Skipped items are ignored, and a function with no answered items returns null rather than a polite zero. On a jungian functions test, an unanswered item is missing data, not neutrality. Four statements per function is demo-sized; a production mbti cognitive functions test would use more items without changing this shape. Since the mbti cognitive functions test scores agreement, keep statement wording behavioral ("I notice…") rather than identity claims.

Deriving MBTI function stacks from a four-letter code

No lookup table needed: the mbti function stack falls straight out of the type-dynamics rules. J means you extravert your judging process, P your perceiving one. An extravert leads with that extraverted process; an introvert leads with the other pair turned inward and shows the auxiliary to the world. The tertiary is the opposite process of the auxiliary, though its attitude is debated — the Foundation's answer is basically "You decide from your own experience!" — and the inferior is the dominant's opposite in every way. That is all an mbti cognitive functions test needs to build every stack on the fly.

Diagram deriving the INFJ function stack Ni Fe Ti Se from its four letters

const OPP = { S: 'N', N: 'S', T: 'F', F: 'T' };
const flip = a => (a === 'e' ? 'i' : 'e');

function stackFromCode(code) {                // e.g. 'INFJ'
  const [ei, sn, tf, jp] = code.toUpperCase().split('');
  // The last letter names the process you extravert: J -> T/F, P -> S/N
  const outward = jp === 'J' ? tf : sn;
  const inward = jp === 'J' ? sn : tf;
  const dom = ei === 'E' ? outward + 'e' : inward + 'i';
  const aux = ei === 'E' ? inward + 'i' : outward + 'e';
  const ter = OPP[aux[0]] + dom[1];           // one convention; the tertiary's attitude is debated
  const inf = OPP[dom[0]] + flip(dom[1]);     // opposite of the dominant in every way
  return [dom, aux, ter, inf];
}
// stackFromCode('INFJ') -> ['Ni', 'Fe', 'Ti', 'Se']
// stackFromCode('ENFP') -> ['Ne', 'Fi', 'Te', 'Si']
Enter fullscreen mode Exit fullscreen mode

One comment in that code is doing honest work: the tertiary's attitude is a convention here, not scripture. The rules also have a satisfying symmetry — every function is dominant for exactly two types. Ni leads INFJ and INTJ, Se leads ESTP and ESFP, Fi leads ISFP and INFP, and so on. That symmetry is trivial to assert in a unit test, and an mbti cognitive functions test built on these rules gets it for free. Because mbti function stacks are derived rather than stored, the mbti cognitive functions test never carries a stale table someone could mistype.

Scoring a Myers Briggs cognitive functions test

Now the scoring step of the mbti cognitive functions test: compare the answer profile against every type's stack, with the dominant counting most and the inferior least. I use weights 4/3/2/1 and a 0.25 tie band — both are design choices for this mbti cognitive functions test, not a standard, so print them next to the results.

const WEIGHTS = [4, 3, 2, 1];                 // dominant .. inferior (a design choice)
const TYPES = ['ISTJ', 'ISFJ', 'INFJ', 'INTJ', 'ISTP', 'ISFP', 'INFP', 'INTP',
               'ESTP', 'ESFP', 'ENFP', 'ENTP', 'ESTJ', 'ESFJ', 'ENFJ', 'ENTJ'];

function rankTypes(fnScores, tieBand = 0.25) {
  const ranked = TYPES.map(code => ({
    code,
    fit: stackFromCode(code).reduce((s, fn, i) => s + WEIGHTS[i] * (fnScores[fn] ?? 0), 0),
  })).sort((a, b) => b.fit - a.fit);
  const top = ranked.filter(t => ranked[0].fit - t.fit <= tieBand);
  return { ranked, top };                     // top.length > 1 means "show the tie"
}
Enter fullscreen mode Exit fullscreen mode

A worked example with illustrative scores: Ni +0.75, Fe +0.50, Ne +0.50, Ti +0.25, Se -0.50, everything else 0. INFJ computes as 4(0.75) + 3(0.50) + 2(0.25) + 1(-0.50) = 4.5. Here are the top five, which is the table an mbti cognitive functions test should show:

Type Stack Fit
INFJ Ni Fe Ti Se 4.5
ENTP Ne Ti Fe Si 3.75
ENFJ Fe Ni Se Ti 3.5
ESFJ Fe Si Ne Ti 3.25
INTP Ti Ne Si Fe 3.0

This table is where an mbti cognitive functions test earns or loses trust, and it surprised me the first time I ran it. ENTP comes second, ahead of ENFJ, even though ENTP shares neither of INFJ's lead functions. It collects points from Ne in first place and Fe in third, and nothing in its stack is negative. ENFJ shares Ni and Fe with INFJ in reverse order, but it pays for Se sitting in third place. That is the mbti cognitive functions test's weighted sum doing exactly what it was told, and a reminder that the weights are an opinion. The 0.75 gap to second place sits outside the tie band, so top holds one type here. If you're building a function test MBTI fans will actually trust, show this arithmetic instead of only the winner. For a contrasting philosophy, compare a Jung-inspired test that openly skips function stacks — its page states it does not measure the eight cognitive functions and that no self-report preference quiz can. That's a refreshing thing to read on a quiz page.

Ties and unit tests for your mbti cognitive functions test

With only four items per function, near-ties are common, so ties get first-class handling in any mbti cognitive functions test and the rules get tests. Three cover what breaks silently:

import { test, expect } from 'vitest';

test('INFJ stack follows the type-dynamics rules', () => {
  expect(stackFromCode('INFJ')).toEqual(['Ni', 'Fe', 'Ti', 'Se']);
});

test('each function is dominant for exactly two types', () => {
  const doms = TYPES.map(t => stackFromCode(t)[0]);
  for (const fn of FUNCTIONS) expect(doms.filter(d => d === fn)).toHaveLength(2);
});

test('all-neutral answers produce a full tie, not a type', () => {
  const answers = Object.fromEntries(items.map(i => [i.id, 3]));
  expect(rankTypes(scoreFunctions(answers)).top).toHaveLength(16);
});
Enter fullscreen mode Exit fullscreen mode

The first locks the mbti cognitive functions test to a known stack. The second asserts that symmetry from earlier: each function is dominant for exactly two of the sixteen types. The third is my favorite — if every answer is neutral, all sixteen types tie and top comes back with sixteen entries, forcing the UI to show a tie instead of inventing a winner. An mbti cognitive functions test that returns a confident type from all-neutral input is broken somewhere in its centering, and this catches it loudly.

What I would not ship in an mbti cognitive functions test

Three rules I hold before shipping any mbti cognitive functions test:

  • No "accuracy %". Nothing here was validated against anything, so a percentage would be theater. Show the fit numbers and the tie band instead.
  • No unstated weights. Fixed weights like 4/3/2/1 are fine; shipping them silently turns the mbti cognitive functions test into a black box. Print them.
  • Show ties. If top.length > 1, render every tied type. Forcing one letter out of a quarter-point difference is where an mbti cognitive functions test starts lying.

I took a slower pass at the preference-pair side of this in How to build a personality test in JavaScript, which covers neutral answers and the same test-first habits. The mbti cognitive functions test in this post is the layer underneath. If there is a lesson, it is that an honest mbti cognitive functions test is careful plumbing plus a refusal to overclaim.

Editor's note from Nico: I help out with PersonalityTest, so I'm biased toward quizzes that admit their limits. This is a scoring exercise, not a claim that a self-report can see your functions.

To see that philosophy running, try the free MBTI-style test: 32 original statements, scored entirely in the browser, answers never uploaded, no account or email gate — and when a pair lands near the middle it says "balanced" and shows neighboring codes instead of forcing a letter. It is the same honesty the mbti cognitive functions test above is aiming for.

PersonalityTest is unofficial and not affiliated with The Myers-Briggs Company or the Myers & Briggs Foundation. The code here was written for this article.

Top comments (0)