-
Notifications
You must be signed in to change notification settings - Fork 5.6k
feat(mobile): add subscription usage home screen widgets #10055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
saphid
wants to merge
5
commits into
pingdotgg:main
Choose a base branch
from
saphid:feat/mobile-subscription-widgets
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
9b8583f
feat(mobile): add subscription usage home screen widgets
github-actions[bot] 90c4db9
fix(mobile): satisfy native widget lint rules
github-actions[bot] 0980196
fix(mobile): persist unavailable quotas in iOS widgets
github-actions[bot] 9ef2617
fix(mobile): expire widget readings with invalid timestamps
github-actions[bot] b3d4d18
fix(mobile): keep email-bearing instance names off usage widgets
saphid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
apps/mobile/modules/t3-subscription-widget/android/build.gradle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| apply plugin: 'com.android.library' | ||
| apply plugin: 'org.jetbrains.kotlin.android' | ||
|
|
||
| group = 'com.t3tools.subscriptionwidget' | ||
| version = '0.0.0' | ||
|
|
||
| android { | ||
| namespace 'expo.modules.t3subscriptionwidget' | ||
| compileSdk rootProject.ext.compileSdkVersion | ||
| defaultConfig { | ||
| minSdkVersion rootProject.ext.minSdkVersion | ||
| targetSdkVersion rootProject.ext.targetSdkVersion | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| implementation project(':expo-modules-core') | ||
| } |
8 changes: 8 additions & 0 deletions
8
apps/mobile/modules/t3-subscription-widget/android/src/main/AndroidManifest.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <application> | ||
| <receiver android:name="expo.modules.t3subscriptionwidget.SubscriptionUsageWidget" android:exported="false" android:label="@string/t3_subscription_widget_name"> | ||
| <intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /></intent-filter> | ||
| <meta-data android:name="android.appwidget.provider" android:resource="@xml/t3_subscription_widget_info" /> | ||
| </receiver> | ||
| </application> | ||
| </manifest> |
124 changes: 124 additions & 0 deletions
124
...widget/android/src/main/java/expo/modules/t3subscriptionwidget/SubscriptionUsageWidget.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| package expo.modules.t3subscriptionwidget | ||
|
|
||
| import android.app.PendingIntent | ||
| import android.appwidget.AppWidgetManager | ||
| import android.appwidget.AppWidgetProvider | ||
| import android.content.ComponentName | ||
| import android.content.Context | ||
| import android.content.Intent | ||
| import android.net.Uri | ||
| import android.os.Bundle | ||
| import android.view.View | ||
| import android.widget.RemoteViews | ||
| import org.json.JSONObject | ||
| import java.text.DateFormat | ||
| import java.util.Date | ||
|
|
||
| class SubscriptionUsageWidget : AppWidgetProvider() { | ||
| override fun onUpdate(context: Context, manager: AppWidgetManager, ids: IntArray) { | ||
| ids.forEach { update(context, manager, it) } | ||
| } | ||
|
|
||
| override fun onAppWidgetOptionsChanged( | ||
| context: Context, | ||
| manager: AppWidgetManager, | ||
| id: Int, | ||
| options: Bundle | ||
| ) { | ||
| update(context, manager, id) | ||
| } | ||
|
|
||
| companion object { | ||
| const val PREFERENCES = "t3_subscription_widget" | ||
|
|
||
| fun updateAll(context: Context) { | ||
| val manager = AppWidgetManager.getInstance(context) | ||
| manager.getAppWidgetIds(ComponentName(context, SubscriptionUsageWidget::class.java)) | ||
| .forEach { update(context, manager, it) } | ||
| } | ||
|
|
||
| private fun update(context: Context, manager: AppWidgetManager, id: Int) { | ||
| val saved = context.getSharedPreferences(PREFERENCES, 0).getString("snapshot", null) | ||
| val snapshot = try { | ||
| saved?.let { JSONObject(it) } | ||
| } catch (_: Exception) { | ||
| null | ||
| } | ||
| val views = RemoteViews(context.packageName, R.layout.t3_subscription_widget) | ||
| openAppIntent(context, id, snapshot)?.let { | ||
| views.setOnClickPendingIntent(R.id.t3_widget_root, it) | ||
| } | ||
| val rows = snapshot?.optJSONArray("rows") | ||
| if (rows != null && rows.length() > 0) { | ||
| views.removeAllViews(R.id.t3_widget_rows) | ||
| val options = manager.getAppWidgetOptions(id) | ||
| val height = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 180) | ||
| val count = ((height - 64) / 66).coerceIn(1, 8).coerceAtMost(rows.length()) | ||
| var oldest = Long.MAX_VALUE | ||
| for (index in 0 until count) { | ||
| val row = rows.optJSONObject(index) ?: continue | ||
| val child = rowView(context, row) | ||
| oldest = minOf(oldest, row.optLong("checkedAt")) | ||
| views.addView(R.id.t3_widget_rows, child) | ||
| } | ||
| val remaining = (snapshot?.optInt("totalRows", rows.length()) ?: rows.length()) - count | ||
| val formatted = DateFormat.getDateTimeInstance( | ||
| DateFormat.SHORT, | ||
| DateFormat.SHORT | ||
| ).format(Date(oldest)) | ||
| val more = if (remaining > 0) { | ||
| context.getString(R.string.t3_subscription_widget_more, remaining) | ||
| } else { | ||
| "" | ||
| } | ||
| views.setTextViewText( | ||
| R.id.t3_widget_footer, | ||
| ( | ||
| if (oldest > 0) { | ||
| context.getString(R.string.t3_subscription_widget_as_of, formatted) | ||
| } else { | ||
| context.getString(R.string.t3_subscription_widget_unknown_check) | ||
| } | ||
| ) + more | ||
| ) | ||
| } | ||
| manager.updateAppWidget(id, views) | ||
| } | ||
|
|
||
| private fun openAppIntent(context: Context, id: Int, snapshot: JSONObject?): PendingIntent? { | ||
| // Target this variant's launcher so co-installed builds cannot steal the tap. | ||
| val intent = | ||
| context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return null | ||
| intent.action = Intent.ACTION_VIEW | ||
| val deepLink = snapshot?.optString("deepLink")?.takeIf { it.isNotBlank() } | ||
| ?: "t3code://settings/usage?tab=limits" | ||
| intent.data = Uri.parse(deepLink) | ||
| intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP | ||
| return PendingIntent.getActivity( | ||
| context, | ||
| id, | ||
| intent, | ||
| PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE | ||
| ) | ||
| } | ||
|
|
||
| private fun rowView(context: Context, row: JSONObject): RemoteViews { | ||
| val child = RemoteViews(context.packageName, R.layout.t3_subscription_widget_row) | ||
| val used = if (row.isNull("usedPercent")) null else row.optInt("usedPercent").coerceIn(0, 100) | ||
| child.setTextViewText(R.id.t3_widget_label, row.optString("label")) | ||
| child.setTextViewText(R.id.t3_widget_window, row.optString("window")) | ||
| val percent = used?.let { context.getString(R.string.t3_subscription_widget_used, it) } ?: "—" | ||
| child.setTextViewText(R.id.t3_widget_percent, percent) | ||
| val visibility = if (used == null) View.GONE else View.VISIBLE | ||
| child.setViewVisibility(R.id.t3_widget_progress, visibility) | ||
| if (used != null) child.setProgressBar(R.id.t3_widget_progress, 100, used, false) | ||
| val reset = if (row.optLong("expiresAt") <= System.currentTimeMillis()) { | ||
| context.getString(R.string.t3_subscription_widget_refresh) | ||
| } else { | ||
| row.optString("resetLabel") | ||
| } | ||
| child.setTextViewText(R.id.t3_widget_reset, reset) | ||
| return child | ||
| } | ||
| } | ||
| } |
18 changes: 18 additions & 0 deletions
18
...get/android/src/main/java/expo/modules/t3subscriptionwidget/T3SubscriptionWidgetModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package expo.modules.t3subscriptionwidget | ||
|
|
||
| import expo.modules.kotlin.modules.Module | ||
| import expo.modules.kotlin.modules.ModuleDefinition | ||
| import org.json.JSONObject | ||
|
|
||
| class T3SubscriptionWidgetModule : Module() { | ||
| override fun definition() = ModuleDefinition { | ||
| Name("T3SubscriptionWidget") | ||
| Function("updateSnapshot") { snapshot: String -> | ||
| val context = appContext.reactContext ?: return@Function | ||
| JSONObject(snapshot) // Reject malformed writes before replacing the saved snapshot. | ||
| context.getSharedPreferences(SubscriptionUsageWidget.PREFERENCES, 0) | ||
| .edit().putString("snapshot", snapshot).apply() | ||
| SubscriptionUsageWidget.updateAll(context) | ||
| } | ||
| } | ||
| } |
4 changes: 4 additions & 0 deletions
4
...3-subscription-widget/android/src/main/res/drawable/t3_subscription_widget_background.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <solid android:color="@color/t3_widget_background" /> | ||
| <corners android:radius="20dp" /> | ||
| </shape> |
9 changes: 9 additions & 0 deletions
9
...ile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:id="@+id/t3_widget_root" android:layout_width="match_parent" android:layout_height="match_parent" | ||
| android:orientation="vertical" android:padding="16dp" android:background="@drawable/t3_subscription_widget_background"> | ||
| <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/t3_subscription_widget_name" android:textStyle="bold" android:textSize="16sp" android:textColor="@color/t3_widget_foreground" android:maxLines="1" android:ellipsize="end" /> | ||
| <LinearLayout android:id="@+id/t3_widget_rows" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical"> | ||
| <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/t3_subscription_widget_empty" android:textSize="13sp" android:textColor="@color/t3_widget_secondary" /> | ||
| </LinearLayout> | ||
| <TextView android:id="@+id/t3_widget_footer" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/t3_subscription_widget_open" android:textSize="10sp" android:textColor="@color/t3_widget_secondary" android:maxLines="1" android:ellipsize="end" /> | ||
| </LinearLayout> |
10 changes: 10 additions & 0 deletions
10
...modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget_row.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="8dp"> | ||
| <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> | ||
| <TextView android:id="@+id/t3_widget_label" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:textSize="12sp" android:textStyle="bold" android:textColor="@color/t3_widget_foreground" android:maxLines="1" android:ellipsize="end" /> | ||
| <TextView android:id="@+id/t3_widget_percent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="8dp" android:textSize="12sp" android:textColor="@color/t3_widget_foreground" /> | ||
| </LinearLayout> | ||
| <TextView android:id="@+id/t3_widget_window" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="10sp" android:textColor="@color/t3_widget_secondary" android:maxLines="1" android:ellipsize="end" /> | ||
| <ProgressBar android:id="@+id/t3_widget_progress" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="100" android:progressTint="#0284c7" /> | ||
| <TextView android:id="@+id/t3_widget_reset" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="10sp" android:textColor="@color/t3_widget_secondary" android:maxLines="1" android:ellipsize="end" /> | ||
| </LinearLayout> |
5 changes: 5 additions & 0 deletions
5
apps/mobile/modules/t3-subscription-widget/android/src/main/res/values-night/colors.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <resources> | ||
| <color name="t3_widget_background">#18181B</color> | ||
| <color name="t3_widget_foreground">#FAFAFA</color> | ||
| <color name="t3_widget_secondary">#A1A1AA</color> | ||
| </resources> |
5 changes: 5 additions & 0 deletions
5
apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/colors.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <resources> | ||
| <color name="t3_widget_background">#FAFAFA</color> | ||
| <color name="t3_widget_foreground">#18181B</color> | ||
| <color name="t3_widget_secondary">#52525B</color> | ||
| </resources> |
11 changes: 11 additions & 0 deletions
11
apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/strings.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <resources> | ||
| <string name="t3_subscription_widget_unknown_check">Last checked unavailable</string> | ||
| <string name="t3_subscription_widget_name">Subscription usage</string> | ||
| <string name="t3_subscription_widget_description">Saved subscription quotas from your T3 Code environments. Tap to refresh in the app.</string> | ||
| <string name="t3_subscription_widget_empty">Open T3 Code and connect an environment to see limits.</string> | ||
| <string name="t3_subscription_widget_open">Tap to open Usage</string> | ||
| <string name="t3_subscription_widget_refresh">Open app to refresh</string> | ||
| <string name="t3_subscription_widget_used">%1$d%% used</string> | ||
| <string name="t3_subscription_widget_as_of">As of %1$s</string> | ||
| <string name="t3_subscription_widget_more"> · +%1$d more</string> | ||
| </resources> |
9 changes: 9 additions & 0 deletions
9
...e/modules/t3-subscription-widget/android/src/main/res/xml/t3_subscription_widget_info.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:minWidth="250dp" android:minHeight="180dp" | ||
| android:minResizeWidth="180dp" android:minResizeHeight="130dp" | ||
| android:targetCellWidth="4" android:targetCellHeight="3" | ||
| android:resizeMode="horizontal|vertical" android:widgetCategory="home_screen" | ||
| android:updatePeriodMillis="1800000" | ||
| android:description="@string/t3_subscription_widget_description" | ||
| android:initialLayout="@layout/t3_subscription_widget" | ||
| android:previewLayout="@layout/t3_subscription_widget" /> |
4 changes: 4 additions & 0 deletions
4
apps/mobile/modules/t3-subscription-widget/expo-module.config.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "platforms": ["android"], | ||
| "android": { "modules": ["expo.modules.t3subscriptionwidget.T3SubscriptionWidgetModule"] } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import { describe, expect, it, vi } from "vite-plus/test"; | ||
| vi.mock("@expo/ui/swift-ui", () => | ||
| Object.fromEntries( | ||
| ["HStack", "ProgressView", "Spacer", "Text", "VStack"].map((name) => [name, name]), | ||
| ), | ||
| ); | ||
| vi.mock("@expo/ui/swift-ui/modifiers", () => | ||
| Object.fromEntries( | ||
| ["font", "foregroundStyle", "lineLimit", "tint", "widgetURL"].map((name) => [ | ||
| name, | ||
| (value: unknown) => ({ [name]: value }), | ||
| ]), | ||
| ), | ||
| ); | ||
| vi.mock("expo-widgets", () => ({ createWidget: (name: string) => ({ name }) })); | ||
| import { SubscriptionUsage } from "./SubscriptionUsage"; | ||
| import type { SubscriptionUsageSnapshot } from "./subscriptionUsageSnapshot"; | ||
|
|
||
| const now = Date.parse("2026-09-05T12:00:00Z"); | ||
| const snapshot: SubscriptionUsageSnapshot = { | ||
| deepLink: "t3code-dev://settings/usage?tab=limits", | ||
| totalRows: 8, | ||
| rows: Array.from({ length: 8 }, (_, index) => ({ | ||
| label: `Provider ${index}`, | ||
| window: "Weekly", | ||
| usedPercent: 90, | ||
| resetLabel: "Resets tomorrow", | ||
| checkedAt: now, | ||
| expiresAt: now + 600_000, | ||
| })), | ||
| }; | ||
|
|
||
| describe("iOS subscription widget", () => { | ||
| it.each([ | ||
| ["systemSmall", 1], | ||
| ["systemMedium", 2], | ||
| ["systemLarge", 4], | ||
| ] as const)("bounds %s content and reports omitted windows", (widgetFamily, count) => { | ||
| const tree = JSON.stringify( | ||
| SubscriptionUsage(snapshot, { date: new Date(now), widgetFamily, configuration: undefined }), | ||
| ); | ||
| expect(tree).toContain(`Provider ${count - 1}`); | ||
| expect(tree).not.toContain(`Provider ${count}`); | ||
| expect(tree).toContain(`+${8 - count} more`); | ||
| expect(tree).toContain(snapshot.deepLink); | ||
| }); | ||
| it("renders gallery props without account data", () => { | ||
| const tree = JSON.stringify( | ||
| SubscriptionUsage({} as SubscriptionUsageSnapshot, { | ||
| date: new Date(now), | ||
| widgetFamily: "systemSmall", | ||
| configuration: undefined, | ||
| }), | ||
| ); | ||
| expect(tree).toContain("connect an environment"); | ||
| expect(tree).not.toContain("Invalid Date"); | ||
| }); | ||
| it("replaces reset copy when the snapshot expires", () => { | ||
| const tree = JSON.stringify( | ||
| SubscriptionUsage(snapshot, { | ||
| date: new Date(now + 600_000), | ||
| widgetFamily: "systemSmall", | ||
| configuration: undefined, | ||
| }), | ||
| ); | ||
| expect(tree).toContain("Open app to refresh"); | ||
| expect(tree).not.toContain("Resets tomorrow"); | ||
| expect(tree).toContain("90% used"); | ||
| }); | ||
| it("renders an omitted quota as unavailable rather than zero", () => { | ||
| const tree = JSON.stringify( | ||
| SubscriptionUsage( | ||
| { | ||
| ...snapshot, | ||
| rows: [ | ||
| { | ||
| label: "Claude", | ||
| window: "No subscription limits", | ||
| resetLabel: "Open app for details", | ||
| checkedAt: 0, | ||
| expiresAt: 0, | ||
| }, | ||
| ], | ||
| totalRows: 1, | ||
| }, | ||
| { date: new Date(now), widgetFamily: "systemSmall", configuration: undefined }, | ||
| ), | ||
| ); | ||
| expect(tree).toContain("—"); | ||
| expect(tree).toContain("No subscription limits"); | ||
| expect(tree).toContain("Last checked unavailable"); | ||
| expect(tree).not.toContain("1970"); | ||
| expect(tree).not.toContain("ProgressView"); | ||
| expect(tree).not.toContain("0% used"); | ||
| }); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.