Skip to content

FEAT: Add a preference management demo whose pages the shared browser tests drive - #952

Merged
Automation51D merged 5 commits into
mainfrom
feature/create-last-demo
Sep 15, 2026
Merged

Automation51D merged 5 commits into
mainfrom
feature/create-last-demo

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds Examples/Cloud/pmp-web, a website whose pages carry the 51Degrees
Preference Management Platform (PMP) and the 51Degrees client script in
every arrangement the shared 51Did browser tests check, twice. Under
/cloud/ the client script comes from the cloud. Under /pipeline/ it comes
from the demo's own 51Degrees Pipeline through FiftyOne.Pipeline.Web,
which is how a website using the .NET web integration serves it. The tests
in selenium-api-tests
(selenium-api-tests#8) drive these pages instead of pages they build themselves. Each
language will serve copies of the same pages, so the same tests check every
language, and every language's web integration, in the same way. Part of
the create last programme, which is tracked internally.

What is in it

Three commits. The first adds the demo with its /cloud/ pages. The second
renames it to pmp-web and reads only the agreed key names. The third adds
the /pipeline/ pages.

Everything the tests rely on is in plain files under wwwroot.

  • wwwroot/js/recorder.js, the first script on every page. It records every
    request, its body, status and response, and every console line into
    window.__51dTest.
  • wwwroot/js/change-watcher.js, which records each change of answer from
    fod.onChange.
  • wwwroot/js/consent-stub.js, a stand-in consent management platform that
    delivers a string granting purposes 1 to 12 when
    window.__51dCmp.deliver() is called.
  • wwwroot/templates/cloud/<route>.html and
    wwwroot/templates/pipeline/<route>.html, one plain HTML page per route in
    each mode with three placeholders, {{RESOURCE_KEY}}, {{CLOUD_ENDPOINT}}
    and {{CLIENT_SCRIPT_URL}}. A pipeline page is its cloud copy with the
    client script tag pointing at /51Degrees.core.js, not async, and one
    sentence saying where the script comes from.
  • Program.cs, Settings.cs and Pages.cs, which read the environment,
    serve wwwroot, answer /cloud/<route> and /pipeline/<route> with the
    template filled, and run the 51Degrees Pipeline only for the pipeline
    pages and the two requests their client script makes, being
    /51Degrees.core.js and /51dpipeline/json.
  • appsettings.json, listing the pipeline's elements, being
    CloudRequestEngine, DeviceDetectionCloudEngine, DidCloudEngine and
    JavaScriptBuilderElement. The resource key and the cloud are filled in
    from the environment, not written in the file.
  • The project in FiftyOne.DeviceDetection.Examples.sln and
    FiftyOne.DeviceDetection.Examples.Core.slnf, and a row in the root
    README's Cloud table.
Route, under /cloud/ and /pipeline/ Carries, after the recorder
common platform, client script
common-script-first client script, platform
change platform, client script, change watcher
two/one, two/two platform, client script, change watcher
consent consent stub, client script
no-platform client script
platform-only platform, no client script tag
named-object platform with data-object-name="fiftyOneData", no client script tag

Every page answers any host name, because the tests open one page as two
sites. The example's README gives the eight rules another language's copy
follows.

Why the pipeline pages' client script tag is not async. The platform
recognises a client script tag already on the page only by the cloud's
address, /api/v4/<resource key>.js. Where an async /51Degrees.core.js
has not run by the time the document is parsed, the platform adds the
cloud's client script as well, and the page has two. Measured in headless
Chrome against this demo, that happened on 2 of 40 loads with async tags,
and on 12 of 12 when the pipeline's script was held back 1.5 seconds, as a
slow server would. With the tag not async it happened on none of 30 loads.
The .NET web integration's view component writes the tag async by
default, so the platform needs to recognise the web integration's script,
and these tags go back to async when it does.

Environment variables

These are the names agreed for every 51Degrees repository, with the runtime
name read first and the CI name as the fallback.

The names follow the one scheme agreed for every repository, being the
runtime name a developer sets first and the continuous integration name for
the product the demo needs after it.

  • 51DEGREES_RESOURCE_KEY, then _51DEGREES_RESOURCE_KEY_51DID. The
    underscore is there because a shell cannot export a name starting with a
    digit.
  • 51DEGREES_CLOUD_ENDPOINT, given with or without /api/v4/, defaulting
    to https://cloud.51degrees.com.
  • ASPNETCORE_URLS for the address to listen on.

No licence key is read, because the resource key has to carry the 51Did
product itself. Neither value is written to the console.

How it was checked

Locally, against a cloud service built from the create last branches on
localhost, whose client script came from javascript-templates eb02894
through FiftyOne.Pipeline.JavaScriptBuilder 4.5.105-createlast.1. The
/pipeline/ pages ran against locally packed 4.5.105-createlast.1
packages of the pipeline and FiftyOne.Did.Cloud, pinned only in files
that are not committed.

  • /cloud/. Before the rename, the suite's Browser51Did category
    started the demo itself and gave 15 tests, 14 passed, 1 skipped and 0
    failed, in two separate runs. The skip is the IsGdpr test, which stays
    inconclusive until IsGdpr reaches the cloud service. After the
    rename, every /cloud/ route on both site-a.localtest and
    site-b.localtest answered 200 with the scripts in the contract's order,
    every platform attribute in order, no placeholder left and the three
    scripts served byte for byte, and unknown routes answered 404.
  • /pipeline/. Every route on both site names answered with the same
    markup as its cloud copy apart from the client script, which was
    /51Degrees.core.js. That script carried 51Degrees: the maximum of once
    and __51d_pmp seven times, and posts to /51dpipeline/json. On
    /pipeline/common in headless Chrome the first request carried no
    answer, pressing standard sent exactly one more carrying
    id.usage=standard, and a 51Did came back.
  • The suite in /pipeline/ mode gave 15 tests, 8 passed, 6 failed and
    1 skipped, twice. Five failures are the share card not appearing, which
    the same service showed on /cloud/ pages at the same time after its
    platform was rebuilt with the rule that the second card needs third party
    cookies confirmed, so they wait on that rule and the service's data rather
    than on this demo. The sixth is the test of the platform adding the client
    script, which in /pipeline/ mode looks for that script's requests on the
    pipeline's path although the platform adds the cloud's script, and needs a
    change in the suite. On that page the added script's answer went to the
    cloud's /api/v4/json and a 51Did came back.
  • dotnet build -c Release from clean gave 0 warnings and 0 errors at each
    commit.
  • utm-lint.ps1 from common-ci was clean at each commit.

Not in this pull request

  • Released packages for the /pipeline/ pages. The project references the
    released FiftyOne.Pipeline.Web 4.5.104 and FiftyOne.Did.Cloud 4.5.104,
    which render no user prompt block, so those pages show the create last
    behaviour only once the builder change
    (pipeline-dotnet#416)
    is released and the pins move.
  • The platform recognising the web integration's client script, which lets
    the pipeline pages go back to async tags.

Depends on

The pages load the platform, and under /cloud/ the client script, from the
cloud, so they show the create last behaviour only once the cloud release
carrying it is live. It merges together with the shared suite pull request, after that cloud release.

Review follow up, 15 September 2026

Two commits on Examples/Cloud/pmp-web/README.md, taking the head to
f4d3198. New shared property lists were registered this morning, and the
README was sending a reader to the Configurator's front page, which opens
with nothing chosen.

  • 85226fd, the properties the key has to carry are named. The README
    told a reader to create a resource key and never said what has to be on
    it, so a key that generates cleanly can still leave the demo with no user
    prompt block and no second card, which reads as a broken demo. It now says
    the key has to carry the 51Did properties, which is what makes the cloud
    include the part of the client script that asks the visitor how their data
    may be used, and that it has to carry ThirdPartyCookiesEnabled and
    ThirdPartyCookiesEnabledJavaScript, without which the platform never
    tests the third party cookie and the second card never appears. The
    sentence about the console now names the resource key and the cloud
    address rather than saying "either value", which had stopped pointing at
    the two environment variables once text sat between them.
  • f4d3198, the link is the ready made list. The link is now
    https://configure.51degrees.com/YldpCKbW, carrying the same five
    campaign parameters in the same order with the same content and term
    slugs, because this repository's lint requires them.

How the two were checked.

  • GET https://configure.51degrees.com/props/YldpCKbW returns 64 names,
    read at 14:05 today. Every property the README names was confirmed present
    in that response, being the six 51Did properties,
    device.ThirdPartyCookiesEnabled,
    device.ThirdPartyCookiesEnabledJavaScript, device.PlatformName,
    device.PlatformVersion, device.BrowserName, device.BrowserVersion
    and derived.HumanConfidence.
  • Both the plain link and the tagged link answer 200, checked with
    curl -sIL -o /dev/null -w '%{http_code}'.
  • The claim that the pages and the browser tests read fodid.idprobglobal
    was read from wwwroot/js/change-watcher.js, which passes data.fodid to
    the recorder, and from the shared browser suite's own visitor helper,
    which reads idprobglobal off the page object.
  • utm-lint.ps1 -RepoRoot . -Campaign device-detection-dotnet-examples
    reports clean, and the key scan reports
    keys found in the commits to push: 0.

Neither commit touches code, so no build or test result changes. Nothing
else in the body above is made false by these two.

…drive

Adds Examples/Cloud/PreferenceManagement-Web, a website whose pages carry
the 51Degrees Preference Management Platform and the client script in
every arrangement the shared 51Did browser tests in selenium-api-tests
check. Each language will serve copies of the same pages, so the same
tests can check every language.

Everything the tests rely on is in plain files under wwwroot. Three
scripts in wwwroot/js are served unchanged, being the recorder every page
loads first, the change watcher and a stand-in consent management
platform. One HTML template per page in wwwroot/templates/cloud carries
three placeholders, RESOURCE_KEY, CLOUD_ENDPOINT and CLIENT_SCRIPT_URL.
The program only serves wwwroot and answers /cloud/<route> with the
template filled, so another language copies wwwroot and writes a small
filler following the rules in the example's README.

The routes are common, common-script-first, change, two/one, two/two,
consent, no-platform, platform-only and named-object. Every page answers
any host name, because the tests open one page as two sites.

The input data comes from 51DEGREES_RESOURCE_KEY and
51DEGREES_CLOUD_ENDPOINT, with this repository's existing names read when
those are not set, and the endpoint may be given with or without the
/api/v4/ path. Neither value is written to the console.

The /pipeline/ pages, where the dotnet web integration serves the client
script, are not part of this commit.
Moves Examples/Cloud/PreferenceManagement-Web to Examples/Cloud/pmp-web,
with the project file, assembly name and namespace shortened to match
(FiftyOne.Examples.Cloud.PmpWeb), the solution, solution filter and
root README row updated, and every campaign slug carrying the new name.

The resource key is read from 51DEGREES_RESOURCE_KEY and then only from
_51DEGREES_RESOURCE_KEY_51DID, the name continuous integration sets for a
key carrying the 51Did product. The cloud is read from
51DEGREES_CLOUD_ENDPOINT alone. The fallbacks to _51DEGREES_RESOURCE_KEY,
SUPER_RESOURCE_KEY, 51D_CLOUD_ENDPOINT and FIFTYONE_CLOUD_ENDPOINT are
removed, and the README says why the continuous integration name starts
with an underscore.
…rom the demo's own pipeline

Each route is now also answered under /pipeline/, where the preference
platform still loads from the cloud and the client script is
/51Degrees.core.js on the page's own site, served by FiftyOne.Pipeline.Web.
The pipeline is a cloud request engine given the same resource key and
cloud as the pages, the device detection and 51Did cloud engines, and the
JavaScript builder, listed in appsettings.json. It runs only for the
pipeline pages, the script and /51dpipeline/json, so a /cloud/ page never
makes the demo call the cloud as well.

The pipeline pages are the cloud pages with the client script tag pointed
at /51Degrees.core.js and not async, and one sentence saying where the
script comes from. The platform recognises a client script tag already on
the page only by the cloud's /api/v4/<resource key>.js, so an async
pipeline script that has not run once the document is parsed gets the
cloud's client script added beside it. A tag that is not async has always
run by then. The README says so, and that the tag goes back to async once
the platform recognises the web integration's script.

The project references the released FiftyOne.Pipeline.Web,
FiftyOne.DeviceDetection.Cloud and FiftyOne.Did.Cloud packages, which do
not render the user prompt block, so the pipeline pages show the create
last behaviour only once the builder change is released and the pins
move.
The README told a reader to create a resource key and never said what the
key needs on it, so a key that generates cleanly can still leave the demo
with no user prompt block and no second card, which reads as a broken demo.

The key needs the 51Did properties, because the cloud includes the part of
the client script that asks the visitor how their data may be used only for
a key that carries them, which
src/identifiers/pmp/integration.md in the documentation repository states
and the demo's own rule 8 already assumed. The pages and the shared browser
tests read fodid.idprobglobal, in wwwroot/js/change-watcher.js:39 and in
Browser51Did/Visitor.cs of selenium-api-tests.

It also needs ThirdPartyCookiesEnabled and ThirdPartyCookiesEnabledJavaScript,
because without them the platform never tests the third party cookie and the
second card never appears, which is one of the listed reasons on the sharing
page of the documentation.

The sentence about the console now names the resource key and the cloud
address rather than saying either value, which had stopped pointing at the
two environment variables once text sat between them.
The README sent a reader to the Configurator's front page, which opens with
nothing chosen, so a reader had to know which properties the demo needs
before they could generate a key that works.

It now opens the ready made list at
https://configure.51degrees.com/YldpCKbW, which carries 64 properties,
checked with GET /props/YldpCKbW at 14:05 today. The list holds the six
51Did properties, device.ThirdPartyCookiesEnabled and
device.ThirdPartyCookiesEnabledJavaScript, the four factor properties and
derived.HumanConfidence, all confirmed by name against that response.

The five campaign parameters stay exactly as they were, in the order the
lint demands, with the same content and term slugs, and
utm-lint.ps1 -RepoRoot . -Campaign device-detection-dotnet-examples reports
clean. Both the plain link and the tagged link answer 200, checked with
curl -sIL.
@justadreamer
justadreamer marked this pull request as ready for review September 15, 2026 21:00
@Automation51D
Automation51D merged commit 0570718 into main Sep 15, 2026
1 check passed
@Automation51D
Automation51D deleted the feature/create-last-demo branch September 15, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: cleanup Tidying that changes no behaviour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants