Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Notes:
- Prefer `describe` over `RSpec.describe` in specs.
- Do not add `# frozen_string_literal: true` to files.
- Prefer multiple small, individually working commits when possible.
- Always run Rubocop on changed Ruby files.
24 changes: 19 additions & 5 deletions npm-api-maker/__tests__/base-model.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import BaseModel from "../build/base-model.js"
import CustomError from "../build/custom-error"
import {jest} from "@jest/globals"
import {JSDOM} from "jsdom"
import ValidationError from "../build/validation-error.js"
Expand Down Expand Up @@ -42,16 +41,31 @@ describe("BaseModel", () => {
})

describe("parseValidationErrors", () => {
const error = new CustomError("Some validation error", {
const error = new ValidationError({
getUnhandledErrorMessage: () => "Some validation error",
getErrorMessage: () => "Some validation error"
}, {
response: {
validation_errors: []
validation_errors: [{
attribute_name: "name",
attribute_type: "string",
error_messages: ["can't be blank"],
error_types: ["blank"],
input_name: "user[name]",
model_name: "user"
}]
}
})
const form = document.createElement("form")
const model = new BaseModel()
const dispatchEventSpy = jest.spyOn(form, "dispatchEvent").mockImplementation(() => "asd")
const newCustomEventSpy = jest.spyOn(BaseModel, "newCustomEvent").mockImplementation(() => "asd")

beforeEach(() => {
dispatchEventSpy.mockClear()
newCustomEventSpy.mockClear()
})

it("throws the validation errors if no options are given", () => {
expect(() => BaseModel.parseValidationErrors({error, model})).toThrow(ValidationError)
})
Expand All @@ -64,8 +78,8 @@ describe("BaseModel", () => {

it("doesnt throw validation errors if disabled", () => {
BaseModel.parseValidationErrors({error, model, options: {throwValidationError: false}})
expect(dispatchEventSpy).toHaveBeenCalled()
expect(newCustomEventSpy).toHaveBeenCalled()
expect(dispatchEventSpy).not.toHaveBeenCalled()
expect(newCustomEventSpy).not.toHaveBeenCalled()
})
})
})
40 changes: 20 additions & 20 deletions npm-api-maker/__tests__/cable-connection-pool.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import CableConnectionPool from "../buikd/cable-connection-pool.js"
import CableConnectionPool from "../build/cable-connection-pool.js"
import CableSubscriptionPool from "../build/cable-subscription-pool"
import {digg} from "diggerize"
import {jest} from "@jest/globals"
Expand All @@ -12,16 +12,16 @@ describe("CableConnectionPool", () => {
it("creates a new create event and connects", () => {
const cableConnectionPool = new CableConnectionPool()

cableConnectionPool.scheduleConnectUpcoming = function() {
const subscriptionData = this.upcomingSubscriptionData
const subscriptions = this.upcomingSubscriptions
cableConnectionPool.scheduleConnectUpcomingRunLast.queue = () => {
const subscriptionData = cableConnectionPool.upcomingSubscriptionData
const subscriptions = cableConnectionPool.upcomingSubscriptions

this.upcomingSubscriptionData = {}
this.upcomingSubscriptions = {}
cableConnectionPool.upcomingSubscriptionData = {}
cableConnectionPool.upcomingSubscriptions = {}

const cableSubscriptionPool = {subscriptionData, subscriptions}

this.cableSubscriptionPools.push(cableSubscriptionPool)
cableConnectionPool.cableSubscriptionPools.push(cableSubscriptionPool)
}
cableConnectionPool.cableSubscriptionPools = []
cableConnectionPool.connectCreated("Contact", () => console.log("Callback"))
Expand All @@ -48,16 +48,16 @@ describe("CableConnectionPool", () => {
}
}

cableConnectionPool.scheduleConnectUpcoming = function() {
const subscriptionData = this.upcomingSubscriptionData
const subscriptions = this.upcomingSubscriptions
cableConnectionPool.scheduleConnectUpcomingRunLast.queue = () => {
const subscriptionData = cableConnectionPool.upcomingSubscriptionData
const subscriptions = cableConnectionPool.upcomingSubscriptions

this.upcomingSubscriptionData = {}
this.upcomingSubscriptions = {}
cableConnectionPool.upcomingSubscriptionData = {}
cableConnectionPool.upcomingSubscriptions = {}

const cableSubscriptionPool = {subscriptionData, subscriptions}

this.cableSubscriptionPools.push(cableSubscriptionPool)
cableConnectionPool.cableSubscriptionPools.push(cableSubscriptionPool)
}
cableConnectionPool.cableSubscriptionPools = [cableSubscriptionPool]
cableConnectionPool.connectDestroyed("Contact", "modelId", () => { })
Expand Down Expand Up @@ -123,7 +123,7 @@ describe("CableConnectionPool", () => {
this.cableSubscriptionPools.push(cableSubscriptionPool)
}
cableConnectionPool.cableSubscriptionPools = [cableSubscriptionPool]
cableConnectionPool.scheduleConnectUpcoming = () => cableConnectionPool.connectUpcoming()
cableConnectionPool.scheduleConnectUpcomingRunLast.queue = () => cableConnectionPool.connectUpcoming()
cableConnectionPool.connectDestroyed("Contact", "modelId", () => { })

const subscriptions = digg(cableSubscriptionPool, "subscriptions", "Contact", "destroys", "modelId")
Expand All @@ -146,16 +146,16 @@ describe("CableConnectionPool", () => {
}
}

cableConnectionPool.scheduleConnectUpcoming = function() {
const subscriptionData = this.upcomingSubscriptionData
const subscriptions = this.upcomingSubscriptions
cableConnectionPool.scheduleConnectUpcomingRunLast.queue = () => {
const subscriptionData = cableConnectionPool.upcomingSubscriptionData
const subscriptions = cableConnectionPool.upcomingSubscriptions

this.upcomingSubscriptionData = {}
this.upcomingSubscriptions = {}
cableConnectionPool.upcomingSubscriptionData = {}
cableConnectionPool.upcomingSubscriptions = {}

const cableSubscriptionPool = {subscriptionData, subscriptions}

this.cableSubscriptionPools.push(cableSubscriptionPool)
cableConnectionPool.cableSubscriptionPools.push(cableSubscriptionPool)
}
cableConnectionPool.cableSubscriptionPools = [cableSubscriptionPool]
cableConnectionPool.connectUpdate("Contact", "modelId", () => console.log("Update callback"))
Expand Down
14 changes: 10 additions & 4 deletions npm-api-maker/__tests__/collection.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import Collection from "../build/collection.js"

class FakeModel {
static modelClassData() {
return {name: "User"}
}
}

describe("Collection", () => {
describe("count", () => {
it("is able to clone the collection and merge count into it without manipulating the original given query", () => {
let collection = new Collection({}, {})
let collection = new Collection({modelClass: FakeModel}, {})

collection.ransack({name_cont: "Kasper"})

Expand All @@ -19,15 +25,15 @@ describe("Collection", () => {
// This can happen if someone does something like this and users_q isn't set:
// query.ransack(params.users_q)

let collection = new Collection({}, {ransack: {id_eq: 5}})
let collection = new Collection({modelClass: FakeModel}, {ransack: {id_eq: 5}})

collection.ransack(undefined)

expect(collection.queryArgs).toEqual({ransack: {id_eq: 5}})
})

it("handles sorts of different types", () => {
let collection = new Collection({}, {})
let collection = new Collection({modelClass: FakeModel}, {})

collection = collection.ransack({s: "created_at"})
expect(collection.queryArgs.ransack.s).toEqual("created_at")
Expand All @@ -39,7 +45,7 @@ describe("Collection", () => {

describe("selectColumns", () => {
it("adds selected columns to the query", () => {
let collection = new Collection({}, {})
let collection = new Collection({modelClass: FakeModel}, {})

collection = collection.selectColumns({User: ["id"]})
expect(collection.queryArgs.selectColumns).toEqual({user: ["id"]})
Expand Down
2 changes: 1 addition & 1 deletion npm-api-maker/__tests__/custom-error.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe("CustomError", () => {
const customError = new CustomError(`Request failed with code: ${xhr.status}`, {response, xhr})

expect(customError.message).toEqual("Request failed with code: 401")
expect(customError.errorMessages()).toEqual(undefined)
expect(customError.errorMessages()).toEqual(["No error messages found"])
expect(customError.errorTypes()).toEqual(undefined)
})
})
4 changes: 3 additions & 1 deletion npm-api-maker/__tests__/model-name.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import I18nOnSteroids from "i18n-on-steroids"
import Config from "../build/config"
import ModelName from "../build/model-name"

const i18n = new I18nOnSteroids()
Expand All @@ -22,10 +23,11 @@ const initializeI18n = () => {
describe("ModelName", () => {
beforeEach(() => {
initializeI18n()
Config.setI18n(i18n)
})

test("human", () => {
const modelClassData = {i18nKey: "user"}
const modelClassData = {i18nKey: "user", name: "User"}
const modelName = new ModelName({i18n, modelClassData})

expect(modelName.human()).toEqual("Bruger")
Expand Down
25 changes: 17 additions & 8 deletions npm-api-maker/__tests__/routes-native.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const testRoutes = () => ({
{"name": "drinks", "path": "/drinks", "component": "drinks/index"}
]
})
const testTranslations = () => ({
locales: {
const testTranslations = () => {
const locales = {
da: {
routes: {
drink: "drink",
Expand All @@ -27,7 +27,16 @@ const testTranslations = () => ({
}
}
}
})

return {
locales,
t: (key, _unused, {default: defaultValue, locale}) => {
const path = key.split(".").slice(1)
const routeKey = path[path.length - 1]
return locales?.[locale]?.routes?.[routeKey] || defaultValue
}
}
}

const routesNative = ({args, currentLocale}) => {
const test = new RoutesNative({
Expand Down Expand Up @@ -66,14 +75,14 @@ describe("RoutesNative", () => {
const test = routesNative({args: {localized: true}, currentLocale: "en"})
const daRoute = test.editDrinkPath(5, {drink: {name: "Pina Colada"}, locale: "da"})

expect(daRoute).toEqual("/da/drinks/5/rediger?drink%5Bname%5D=Pina%20Colada")
expect(daRoute).toEqual("/da/drinks/5/rediger?drink[name]=Pina+Colada")
})

it("translates a route without localization", () => {
const test = routesNative({currentLocale: "en"})
const daRoute = test.editDrinkPath(5, {drink: {name: "Pina Colada"}})

expect(daRoute).toEqual("/drinks/5/edit?drink%5Bname%5D=Pina%20Colada")
expect(daRoute).toEqual("/drinks/5/edit?drink[name]=Pina+Colada")
})

it("generates urls", () => {
Expand All @@ -85,20 +94,20 @@ describe("RoutesNative", () => {
const test = routesNative({args: {localized: true}, currentLocale: "en"})
const daRoute = test.editDrinkUrl(5, {drink: {name: "Pina Colada"}, locale: "da"})

expect(daRoute).toEqual("http://localhost/da/drinks/5/rediger?drink%5Bname%5D=Pina%20Colada")
expect(daRoute).toEqual("http://localhost/da/drinks/5/rediger?drink[name]=Pina+Colada")
})

it("generates urls with custom options", () => {
const test = routesNative({args: {localized: true}, currentLocale: "en"})
const daRoute = test.editDrinkUrl(5, {drink: {name: "Pina Colada"}, locale: "da", host: "google.com", port: 123, protocol: "https"})

expect(daRoute).toEqual("https://google.com:123/da/drinks/5/rediger?drink%5Bname%5D=Pina%20Colada")
expect(daRoute).toEqual("https://google.com:123/da/drinks/5/rediger?drink[name]=Pina+Colada")
})

it("generates urls without locales", () => {
const test = routesNative({currentLocale: "en"})
const daRoute = test.editDrinkUrl(5, {drink: {name: "Pina Colada"}, locale: "da", host: "google.com", port: 123, protocol: "https"})

expect(daRoute).toEqual("https://google.com:123/drinks/5/edit?drink%5Bname%5D=Pina%20Colada")
expect(daRoute).toEqual("https://google.com:123/drinks/5/edit?drink[name]=Pina+Colada")
})
})
9 changes: 9 additions & 0 deletions npm-api-maker/__tests__/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {TextDecoder, TextEncoder} from "util"

if (!global.TextEncoder) {
global.TextEncoder = TextEncoder
}

if (!global.TextDecoder) {
global.TextDecoder = TextDecoder
}
1 change: 1 addition & 0 deletions npm-api-maker/__tests__/support/actioncable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const createConsumer = () => ({})
1 change: 1 addition & 0 deletions npm-api-maker/__tests__/support/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
module.exports = {
sourceType: "unambiguous",
presets: [
[
"@babel/preset-env",
{
targets: {node: "current"}
}
],
[
"@babel/preset-react",
{
Expand Down
15 changes: 15 additions & 0 deletions npm-api-maker/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
testEnvironment: "jsdom",
testMatch: ["<rootDir>/__tests__/**/*.test.js"],
setupFilesAfterEnv: ["<rootDir>/__tests__/setup.js"],
transform: {
"^.+\\.(cjs|mjs|[jt]sx?)$": ["babel-jest", {configFile: "./babel.config.cjs"}]
},
transformIgnorePatterns: ["/node_modules/(?!epic-locks|i18n-on-steroids)/"],
moduleNameMapper: {
"^\\.\\./build/(.*)$": "<rootDir>/src/$1",
"^\\.\\./\\.\\./build/(.*)$": "<rootDir>/src/$1",
"^@rails/actioncable$": "<rootDir>/__tests__/support/actioncable.js",
"^models\\.js$": "<rootDir>/__tests__/support/models.js"
}
}
8 changes: 4 additions & 4 deletions npm-api-maker/src/model-prop-type.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {digg} from "diggerize"
import Inflection from "inflection"
import * as inflection from "inflection"

export default class ApiMakerModelPropType {
static ofModel (modelClass) {
Expand Down Expand Up @@ -52,7 +52,7 @@ export default class ApiMakerModelPropType {

if (this._withLoadedAbilities) {
for (const abilityName of this._withLoadedAbilities) {
const underscoreAbilityName = Inflection.underscore(abilityName)
const underscoreAbilityName = inflection.underscore(abilityName)

if (!(underscoreAbilityName in model.abilities))
return new Error(`The ability ${abilityName} was required to be loaded in ${propName} of the ${model.constructor.name} type but it wasn't`)
Expand All @@ -62,7 +62,7 @@ export default class ApiMakerModelPropType {
if (this._withLoadedAssociations) {
for (const associationName in this._withLoadedAssociations) {
const associationModelPropType = digg(this._withLoadedAssociations, associationName)
const underscoreAssociationName = Inflection.underscore(associationName)
const underscoreAssociationName = inflection.underscore(associationName)

if (!(underscoreAssociationName in model.relationshipsCache))
return new Error(`The association ${associationName} was required to be loaded in ${propName} of the ${model.constructor.name} type but it wasn't`)
Expand Down Expand Up @@ -92,7 +92,7 @@ export default class ApiMakerModelPropType {

if (this._withLoadedAttributes && model.isPersisted()) {
for (const attributeName of this._withLoadedAttributes) {
const underscoreAttributeName = Inflection.underscore(attributeName)
const underscoreAttributeName = inflection.underscore(attributeName)

if (!(underscoreAttributeName in model.modelData)) {
return new Error(`The attribute ${attributeName} was required to be loaded in ${propName} of the ${model.constructor.name} type but it wasn't`)
Expand Down
9 changes: 7 additions & 2 deletions npm-api-maker/src/table/table.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {digg, digs} from "diggerize"
import {dig, digg, digs} from "diggerize"
import React, {createContext, useContext, useMemo, useRef} from "react"
import {Animated, Platform, Pressable, View} from "react-native"
import BaseComponent from "../base-component"
Expand Down Expand Up @@ -268,12 +268,17 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
async loadCurrentWorkplace() {
const Workplace = modelClassRequire("Workplace")
const result = await Workplace.current()
const currentWorkplace = digg(result, "current", 0)
const currentWorkplace = dig(result, "current", 0)

this.setState({currentWorkplace})
}

async loadCurrentWorkplaceCount() {
if (!this.s.currentWorkplace) {
this.setState({currentWorkplaceCount: 0})
return
}

const WorkplaceLink = modelClassRequire("WorkplaceLink")
const currentWorkplaceCount = await WorkplaceLink
.ransack({
Expand Down
2 changes: 1 addition & 1 deletion ruby-gem/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ PATH
with_advisory_lock

PATH
remote: /home/dev/Development/api_maker/api_maker_table_rubygem
remote: /home/dev/api_maker/api_maker_table_rubygem
specs:
api_maker_table (0.1.1)
acts_as_list
Expand Down
Loading