How find consecutive results in mongoose

imagine I have the next collection:

Files

_id code
randomid ZA/1/1/1-1#1
randomid ZA/1/1/1-1#2
randomid ZA/1/1/1-1#3
randomid ZA/1/1/1-1#10
randomid ZA/1/1/1-1#12
randomid ZA/1/1/1-1#12-1
randomid ZA/1/1/1-1#12-2-1
randomid ZA/1/1/1-1#12-2-2
randomid ZA/1/1/1-1#120

And I’m trying to get the “Childs” using:

Model.find({ code: { $regex: 'ZA/1/1/1-1#12'} })

And what I want:

[
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-1"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-2-1"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-2-2"
    "__v": 0
  },

]

But Im getting (same but including the #120):

[
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-1"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-2-1"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-2-2"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#12-2-2"
    "__v": 0
  },
  {
    "_id": "randomid",
    "code": "ZA/1/1/1-1#120"
    "__v": 0
  },

]

So, that’s why I’m looking for help, how do I prevent this from happening?
Thanks.

react dispatch not being called in a dispatch way or am I missing something

I’m trying to figure out why I’m not able to update state here. I have this so far:


import { items } from "./state";

const { actions } = items;

export const itemActions = {
  ...actions,
  getMyItems(): AppThunk {
    return async (dispatch, getState: any) => {
      const { myItems } = getState().items;
      !myItems?.length && dispatch(uiActions.setLoading(true));
      const { data } = await authClient.get(apis.GetMyItems);
      dispatch(uiActions.setLoading(false));
      if (data) {
        dispatch(itemActions.loadMyItems(data.items));
      } else {
        dispatch(uiActions.showError("Failed to get data"));
      }
    };
  },
  getOtherItems(): AppThunk {
    return async (dispatch, getState: any) => {
      const { otherItems } = getState().items;
      !otherItems?.length && dispatch(uiActions.setLoading(true));
      const { res } = await authClient.get(apis.GetOtherItems);
      dispatch(uiActions.setLoading(false));
      if (res) {
        dispatch(itemActions.loadOtherItems(res.data));
      } else {
        dispatch(uiActions.showError("failed getting other items"));
      }
    };
  },
  saveItem(values): AppThunk {
    return async (dispatch, getState: any) => {
      const { user } = getState().user;
      dispatch(uiActions.setLoading(true));
      const { res } = await authClient.post(
        apis.SaveItem(user.id, values.id),
        values,
      );
      if (res) {
        await dispatch(itemActions.saveItemWorked(values.id));
      } else {
        dispatch(uiActions.showError(res.message ?? "Saving Failed"));
      }
      dispatch(uiActions.setLoading(false));
    };
  },
  saveItemWorked(itemId): AppThunk {
    return async (dispatch, getState: any) => {
      await dispatch(itemActions.getMyItems);
      // this does pretty much the same as getMyItems, but returns other items not included in getMyItems. 
      dispatch(itemActions.getOtherItems(itemId)); 
      dispatch(uiActions.setItemsOpen(false));
      dispatch(uiActions.showSuccess("Item Saved"));
    };
  },
};

When I call it it doesn’t seem to work:

const dispatch = useDispatch();
dispatch(itemActions.saveItem(payload));

I’m seeing the “Item Saved” message and looks like the getOtherItems() is working, but it seems the first api call is not happening. Why is the first one completely ignored?

Testing nodejs with supertest and jest: ReferenceError: You are trying to `import` a file after the Jest environment has been torn down

I have read all post related to this warning message but could not find anything close scenario to mine. I am using supertest along with Jestjs to test my node application. So I am building and testing a task manager app. Initially when I was writing test for user functions I did not have this error until I started the test the task module.
enter image description here

This is the output when I run jest

Because of the ReferenceError problem I am unable to see sample data I pass to mongodb represent in the task collection. This is the code that sends sample data to mongodb

beforeEach((done) => {
  dummySystem.populateData(dummySystem.allocateTasks);
  done();
});

function populateData(callback) {
  User.deleteMany({});
  Task.deleteMany({});
  dummyUserData.forEach((user) => {
    let start = 0;
    let end = 8;
    const userId = mongoose.Types.ObjectId();
    const data = new User({
      ...user,
      _id: userId,
      tokens: [{ flask: jwt.sign({ _id: userId }, process.env.JWT_STRING) }],
    });
    data.save();
    callback(userId, start, end);
    start += 7;
    end += 8;
  });
}
function allocateTasks(id, slice_start, slice_end) {
  if (slice_end < dummyTaskData.length) {
    dummyTaskData.slice(slice_start, slice_end).forEach((task) => {
      const data = new Task({ ...task, crafter: id });
      setTimeout(() => data.save(), 5000);
    });
  }
}

So the sample data comes from a json file. my issue is all the tests are passing and at the same time the is no data in the database. The code below is passing as there are no data in mongodb

test("should login with credentials", function (done) {
  request(server)
    .post("/api/users/login")
    .send({
      email: "[email protected]",
      password: "lanceboginni1",
    })
    .expect(200)
    .then((user) => {
      const storage = User.findById(user._id);
      expects(user.token).toBe(storage.tokens[0].flask);
    });
  done();
});
test("should not authenticate", function (done) {
  request(server)
    .post("/api/users/login")
    .send({
      email: "[email protected]",
      password: "0000",
    })
    .expect(400);
  done();
});

Please help me because I have used all I can find online but it does not work for me and some are also deprecated like add entries to package.json

"jest":{
"timers":"fake"
}

and
jest.useFakeTimers()

I am new to testing so I will really appreciate some help

Accessing query of query loop block from another block, gutenberg wordpress

I’m creating a custom block inside a plugin. It’s a drop down selector of categories for posts. I’m simply trying to update the query of a query loop block on the same page. However I’m not sure how to access the query of the query loop block.

I’ve tried the above however getting the blockId of the block doesn’t seem to be possible on the front end. Does anyone know how i can reference the query loop block from a front end js file?

plugin.php

  function tapacode_selector_ajax_callback() {

    $nonce = $_POST['nonce'];
    if ( ! wp_verify_nonce( $nonce, 'wp-tapacode-nonce' ) ) {
        die ( 'Busted!' );
    }

    $category = intval( $_POST['category']);
    $query_args = array(
        'cat' => $category
    );
    $query = new WP_Query( $query_args );
    wp_send_json( $query->posts );
    wp_die();
}
add_action( 'wp_ajax_tapacode_selector', 'tapacode_selector_ajax_callback' );
add_action( 'wp_ajax_nopriv_tapacode_selector', 'tapacode_selector_ajax_callback' );

add_action( 'wp_enqueue_scripts', 'my_enqueue' );
function my_enqueue() {
    wp_register_script( 'ajax-selector-script', plugins_url( '/selector.js', __FILE__ ), array( 'wp-blocks', 'wp-editor', 'wp-element', 'jquery' ), '1.0', true );
    wp_enqueue_script( 'ajax-selector-script' );

    // in JavaScript, object properties are accessed as ajax_object.ajax_url, ajax_object.we_value
    wp_localize_script( 'ajax-selector-script', 'ajax_object',
            array(
                'ajax_url' => admin_url( 'admin-ajax.php' ),
                'nonce' => wp_create_nonce( 'wp-tapacode-nonce' )
            ) );
}

another plugin.php file

<p <?php echo get_block_wrapper_attributes(); ?>>

selector.js

document.addEventListener('DOMContentLoaded', setupCategorySelector, false);

function setupCategorySelector() {
    document.getElementById('cat').onchange = function () {
        // if value is category id
        if (this.value !== '-1') {
            if (typeof wp !== 'undefined' && wp.data) {
                const blockId = document.querySelector('.wp-block-tapacode-category-selector').getAttribute('data-block-id');
                const queryBlock = wp.data.select('core/block-editor').getBlock(blockId);
                queryBlock.setAttributes({ categories: this.value });
                queryBlock.update();
            }

Why do we return dp[nums.length – 1] instead of dp[nums.length]? Don’t we need the whole array?

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.

Solution:

var rob = function(nums) {
    if (nums === null || nums.length === 0) {
        return 0;
    }
    let dp = new Array(nums.length);
    dp[0] = nums[0];
    dp[1] = Math.max(nums[0], nums[1]);
    for (let i = 2; i < nums.length; i++) {
        dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1]);
    }
    return dp[nums.length - 1];
};

Base case:

  • There’s only 1 house: dp[0] = nums[0];
  • There’s only 2 houses: dp[1] = Math.max(nums[0], nums[1]);

More houses:

let dp = new Array(nums.length);
for (let i = 2; i < nums.length; i++) {
    dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1]);
}

Max of current index + current index – 2 ?

So why are we subtracting 1 at return dp[nums.length-1]?

Object property is unsetting itself

After setting a uuid4 object property either by the Object.assign or Object.defineProperty methods, the property sometimes unsets itself in Safari without explanation, as in the following minimal reproducible example.

I have not observed this issue in Chrome.

To reproduce using this example on a local machine, I would click the “Choose Files” buttons and select files from my local file system. The script preview-uploads.js will then assign the uuid4 property, which uploads-manager.js will subsequently attempt to read and print to console with console.log(file.uuid4).

The example uses local files, so you’ll need to disable local file restrictions in Safari as described here to run this example.

The issue occurs inconsistently in this minimum reproducible example. It took me about 20-30 trials before it occurred again, as confirmed by the screenshot below which shows how console.log(file.uuid4) printed “undefined” to the console. However, in the complicated use case where I am applying it (and which is too big and proprietary to post), it happens nine times out of ten.

There is no obvious pattern that I observe. I’ve paid attention to the file types and file sizes that I’m experimenting with, and the issue bears no obvious correlation to either.

Can someone please help me understand what is causing the property to unset in this apparently random way?

(By the way, the ajax method of building the html is important to my proprietary use case, which is why I’ve included it in the MRE.)

Screenshot

enter image description here

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.js"></script>
</head>
<body>
</body>
<script>
    $(document).ready(function () {
        $.ajax({
            type: 'GET',
            url: 'file:///path/to/test_ajax.html',
            success: function (response) {
                $('body').html(response);
            }
        })
    });
</script>
</html>

test_ajax.html

<script src="/path/to/preview-uploads.js"></script>
<div>
    <div id="files-test1">
        <input autocomplete="off" multiple="true" name="files[]"
               onchange="previewFiles('test1');uploadFiles()" type="file">
    </div>
    <div class="grid-test1 padding-top-15" data-uuid4list="">
        <a href="" target="_blank"><img/>
        </a>
    </div>
</div>
<div>
    <div id="files-test2">
        <input autocomplete="off" multiple="true" name="files[]"
               onchange="previewFiles('test2');uploadFiles()" type="file">
    </div>
    <div class="grid-test2 padding-top-15" data-uuid4list="">
        <a href="" target="_blank">
            <img/>
        </a>
    </div>
</div>
<script src="/Path/to/upload-manager.js"></script>

preview-uploads.js

function previewFiles(fileId) {
  var files   = document.querySelector('[id="files-' + fileId.replace('.','\.') + '"]>input').files;

  if (files) {
    [].forEach.call(files, function(file) {
      let uuid4 = '09832a0d-86c4-4a9f-ab93-23bac596b83b';
      Object.assign(file, {'uuid4': uuid4});    });
  };
};

upload-manager.js

function uploadFiles() {
    var formData = new FormData();
    $("input[type='file']").each(function() {
        $.each(this.files, function(i, file) {
            formData.append('files[]', file, file.uuid4 + ':' + file.name);
            console.log('file.uuid4 will follow next');
            console.log(file.uuid4);
        });
    });
};

Find location of y-axis ticks using d3.js

I am building a SVG visualisation using d3.js (in PowerBI – so version 3 of d3), and I am struggling aligning my data points and fixed lines with the appropriate y-axis tick marker.

For example, with 8 axis points, the lines are almost right, just slightly above

But when there is only 1 or 2 points, it’s way off

enter image description here

I am trying to dynamically calculate the offset as the number of y-axis ticks will depend on the PowerBI filter I have.

My current calculation is that I am taking the height of the svg, dividing it by the number of ticks, and then dividing that by two so it lands in the centre. The y-axis is ordinal.

Relevant code is:

var margin = {top: 20, right: 250, bottom: 50, left: 50},
    width = pbi.width - margin.left - margin.right,
    height = pbi.height - margin.top - margin.bottom,
    legendleft = pbi.width - margin.right;

var y = d3.scale.ordinal()
     .rangeRoundBands([0, height], barPad, barOuterPad);

var svg = d3.select("#chart")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom + legendleft)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

y.domain(Data.map(function(d) { return d.reportingyear; }));

var YearSize = new Set(yearArray).size  // Gets the number of ticks on the y-axis

svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(0, 6)")
    .call(d3.svg.axis().scale(y).orient("left"));

// Chart the rows
  var publishedRow = svg.append("g").attr("id", "publishedgroup").selectAll(null)
      .data(rowArray)
    .enter();

  publishedRow.append("line")
      .style("stroke", "grey") 
      .style("stroke-width", 1)
      .style("stroke-dasharray", ("2, 2"))
      .attr("x1", function(d) { return 0; })
      .attr("y1", function(d) { return y(d.entry)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); })
      .attr("x2", function(d) { return width; })
      .attr("y2", function(d) { return y(d.entry)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); });


publishedRow.append("circle")
      .attr("cx", function(d) {return x(new Date(d.date))} )
      .attr("cy", function(d) {return y(d.year)+((pbi.height-margin.top-margin.bottom) / (new Set(yearArray).size) / 2); })
      .attr("r", 7)
      .style("fill", function(d, i) { return milestoneMap[d.milestone]; })
      });

It is the .attr lines that have the code that dynamically calculates the offset.

Is there an easier way to do this? Or can I get some advice as to why my calculation isn’t working?

Thank you!

CapacitorJS Keyboard covers app in android

I have a capacitor app with Keyboard plugin.
I want to resize the view when I open the keyboard, but it does’t work.
My Config.

import { CapacitorConfig } from '@capacitor/cli'
import { KeyboardResize, KeyboardStyle } from '@capacitor/keyboard'

const config: CapacitorConfig = {
  appId: 'lol.lazar.chat',
  appName: 'SvelteChat',
  webDir: 'build',
  bundledWebRuntime: false,
  plugins: {
    Keyboard: {
      resize: KeyboardResize.Native,
      style: KeyboardStyle.Dark,
      resizeOnFullScreen: true,
    },
  },
}

export default config;

How to avoid repeating complex generics when writing functions?

I have a function that has a pretty complex generic interface as it’s argument:

const defineSchema: DefineSchema = <
  Part extends string,
  Parts extends Tuple<Part>,
  Case extends string,
  Cases extends Tuple<Case>,
  Class extends GramCategory<Part>,
  Classes extends Tuple<Class> | null,
  ClassValue extends GramCatValue<NonNullable<Classes>[number]> = GramCatValue<NonNullable<Classes>[number]>,
>(schema: DeclensionSchema<Part, Parts, Case, Cases, Class, Classes>) => (
  name: { [index in keyof Parts]?: string } | { [key in Parts[number]]?: string },
  gramCase: Case,
  gramClass?: ClassValue,
) => {
   // ...function body
};

The first issue I ran into is that I had to repeat every generic constraint on DeclensionSchema (which is the source of all these generics in the first place), which is undesirable, but bearable.

However, I also want to define function interface (DefineSchema) with overloads, and each overload would require repeating all the generics again, which is again fine by me. But then what if I want extract some piece of code from the function body into a separate function that would require schema as an argument? I would need to copypaste generics yet again…

I hope you see that such architecture can quickly spiral out of control and become hard to read and/or maintain. Is there a solution (a TS feature, or architectural pattern, etc.) that can help in this situation?

As a side note, I believe half of my problems could be solved by simply defining a class with generics, since all code inside of a class has access to the same generics, but I would like to avoid using classes when possible (my use case doesn’t really call for a class).

Broadcasting to everyone except sender socket.io

i am building a chat in my app. I am using socket.io for this. When a user sends a message i send an api request to my server. The api stores the message in the database and only then emits, with a socket service to everyone in the room that there is a new message. I have a SocketService class with this method:

  private async broadcast({ type, data, chatId, senderId }: { type: string; data: any; chatId: string; senderId: string }) {
const excludedSocket = await this.getUserSocket(senderId);
if (chatId && excludedSocket) {
  excludedSocket.emit;
} else if (excludedSocket) {
  excludedSocket.emit(type, data);
} else if (room) {
  gIo.to(room).emit(type, data);
} else {
  gIo.emit(type, data);
}

}

The problem i have is that getUserSocket returns a RemoteSocket object that dont have the broadcast or to methods on it. So how can i achive this?

 private async getUserSocket(userId: string) {
const sockets = await this.getAllSockets();
const socket = sockets.find((s) => s.data.uid === userId);
return socket;

}

private async getAllSockets() {
const sockets = await this.io.fetchSockets();
return sockets

}

Two autocomplete variables, second one should depend on first one – Simple JS

I am sure this question is posted before, but didn’t find it in javascript/jquery.

So I have two inputs, first one is a city, and second one is a part of that specific city that we chose in first input:

$(function() {
  var city = ["option1", "option2", "option3", "option4"];
  $("#city").autocomplete({
    source: city
  });
  var addressforoption1 = ["a1", "a2", "a3", "a4"];

  var addressforoption2 = ["b1", "b2", "b3", "b4"];

  var addressforoption3 = ["c1", "c2", "c3", "c4"];

  var addressforoption4 = ["d1", "d2", "d3", "d4"];

  var answer = querySelector('#city').value;//tried changing this to innerText or innerHTML still the same
  if (answer = "option1") {
    address = addressforoption1
  }
  if (answer = "option2") {
    address = addressforoption2
  }
  if (answer = "option3") {
    address = addressforoption3
  }
  if (answer = "option4") {
    address = addressforoption4
  }
  $("#location").autocomplete({
    source: address
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<label for="city">➡ City<span style="color:red;">*</span></label>
<input type="text" required name="city" id="city" placeholder="Enter your city name here">
<hr>
<label for="location">➡ Location<span style="color:red;">*</span></label>
<input type="text" required name="location" id="location" placeholder="City location">

*For some reason, snippet doesn’t work, but in my website it does.

Problem: First autocomplete works with charm, and you can pick any city you want, exactly like it should. But second autocomplete is always last one – option 4

Bootstrap tooltip feature not working even after initializing in js

My custom tooltip wasn’t displaying at all so I striped my document down to the bare bones and actually plucked an example from the bootstrap website. It still won’t work.

https://jsfiddle.net/swagat123/pwzs397b/2/

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
  </head>
  <body>
    <script>
        const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
        const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
        // const exampleEl = document.getElementById('example');
        // const tooltip = new bootstrap.Tooltip(exampleEl, options);
        
        //Tried this; didn't work:
        // $(function () {
        //     $('[data-toggle="tooltip"]').tooltip()
        // })

    </script>
    <h1>Hello, world!</h1>

    <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Tooltip on top">
        Tooltip on top
      </button>
      <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Tooltip on right">
        Tooltip on right
      </button>
      <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Tooltip on bottom">
        Tooltip on bottom
      </button>
      <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" data-bs-title="Tooltip on left">
        Tooltip on left
      </button>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
  </body>
</html>```


Tried bunch of different examples and different ways of initializing to no avail. I need a tooltip to pop up. 

How to get specific value from HIDDEN html using jQuery

I would like to get GUID value from my hidden html and store it in an array.

My Script gives me below results but I am more after GUID values from all the records.

Here is the script

function SaveButton() {
    var theTable = document.getElementById("tTable");
    var Tablerow = theTable.rows.length;

    let cells = theTable.querySelectorAll('td');
    cells.forEach((cell) => console.log(cell.innerHTML));
    
    }

The output of console is below

<input type="HIDDEN" id="list_rownumber_3" name="list_rownumber_3" value="3"><input type="HIDDEN" id="list_name_3" name="list_name_3" value="ABC"><input type="HIDDEN" id="list_code_3" name="list_code_3" value="D5FAF478-CF43-40E1-BE79-BB90147A3194"><input type="HIDDEN" id="list_comparecode_3" name="list_comparecode_3" value="0105">
ABC
0105

<input type="HIDDEN" id="list_rownumber_2" name="list_rownumber_2" value="2"><input type="HIDDEN" id="list_name_2" name="list_name_2" value="CDE"><input type="HIDDEN" id="list_code_2" name="list_code_2" value="2E79B23E-D264-4901-A065-7E0B7032A5D8"><input type="HIDDEN" id="list_comparecode_2" name="list_comparecode_2" value="0728">
 CDE
 0728

<input type="HIDDEN" id="list_rownumber_1" name="list_rownumber_1" value="1"><input type="HIDDEN" id="list_name_1" name="list_name_1" value="EFG"><input type="HIDDEN" id="list_code_1" name="list_code_1" value="C71F952E-ED74-4138-8061-4B50B9EF6463"><input type="HIDDEN" id="list_comparecode_1" name="list_comparecode_1" value="0090">
EFG
0090

I would like to get only GUID value and store it in an array.

Does requestAnimationFrame() not stop in Firefox when I move away from the tab?

The doc at https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame says:

requestAnimationFrame() calls are paused in most browsers when running in background tabs

What does “background tabs” mean? When I switch from one tab to another, does the older tab become a become a background tab? If so, then the following example does not behave the way the doc says.

In the example below I am using requestAnimationFrame() callback to log the timestamp at which the callback is called. The callback also plays an audio tone to hear whenever it is called.

function playAudio() {
  const ctx = new AudioContext();
  const osc = ctx.createOscillator();
  const startTime = ctx.currentTime;
  const stopTime = startTime + 0.2;
  osc.frequency.value = 440;
  osc.connect(ctx.destination);
  osc.start(startTime);
  osc.stop(stopTime);
}

let lastActionTime = 0;

function action(timestamp) {
  console.log(timestamp);
  window.requestAnimationFrame(action);
  if (timestamp - lastActionTime < 1000) {  // Throttle
    return
  }
  playAudio()
  lastActionTime = timestamp
}

function startAction() {
  window.requestAnimationFrame(action);
}

window.onload = function() {
  const startButton = document.getElementById("start");
  startButton.addEventListener("click", startAction)
}
<button id="start">Start</button>

To run this example, click on the “start” button. An audio tone starts playing every 1 second. Now switch away to another tab. In Firefox, I see that when I move away to another tab the audio tone still keeps playing although with much longer delays. Does this behavior conform to the spec? Shouldn’t requestAnimationFrame stop calling my callback completely when I move away from the tab?