今日已更新 252 条资讯 | 累计 32289 条内容
关于我们

标签:#p

找到 13377 篇相关文章

AI 资讯

The Test That Passes in Staging But Fails When a Customer Runs It

You have been here. The test suite is green. The deployment pipeline reports all checks passed. Then a customer opens a ticket with a screenshot that shows something your test never caught. The test passed in staging. It fails in production. And you cannot reproduce it locally. This is not a flaky test problem. It is a fidelity problem. Your test environment and your production environment are not the same thing. The gap between them is where real bugs live. Let me walk through one concrete example, the fix, and what it teaches about writing tests that survive the handoff to a real user. The Problem: Environment Drift A fintech team I worked with had a checkout flow. The test clicked "Pay Now", waited for a success message, and asserted the text "Payment successful" appeared on screen. It passed every time in staging. Customers reported that after paying, they saw a blank white page for several seconds before the success message appeared. Some of them closed the tab during that blank period, thinking the payment failed. The transaction went through. The customer never saw the confirmation. Support tickets piled up. The test never caught this because the staging environment served the success page in under 200 milliseconds. The blank period did not exist there. Production had a slower downstream service that introduced a three-second delay between the payment confirmation and the page render. The test was correct in what it checked. It was wrong in what it assumed about timing and state. The Fix: Test the Experience, Not Just the Outcome The fix was not to add a longer wait. The fix was to test what the user actually experiences during that gap. Here is a minimal Playwright test in TypeScript that catches this class of problem: import { test , expect } from ' @playwright/test ' ; test ( ' checkout shows loading state before success ' , async ({ page }) => { await page . goto ( ' /checkout ' ); await page . fill ( ' #card-number ' , ' 4111111111111111 ' ); await page

2026-07-21 原文 →
AI 资讯

Is Your BDD Framework Just a Fancy Way to Write Manual Test Cases in Gherkin?

Gherkin is not a test automation tool. It never was. Yet here we are, five years into your SDET career, and you're staring at a feature file that reads like a step-by-step manual for a human tester. Given I log in with username "admin" and password "password123" . When I click the "Submit" button . Then I see the text "Welcome" on the screen . You've written two years of these. Your team calls it BDD. Your manager calls it "living documentation." And somewhere in the back of your mind, a quiet voice whispers: This is just a manual test case with extra steps. That voice is right. Let me say it plainly: if your Gherkin scenarios describe how the system works instead of what it should do, you are not doing BDD. You are writing manual test cases in a structured English format and calling it automation. The only thing you've automated is the illusion of progress. The problem isn't Gherkin. The problem is how we use it. Most teams adopt BDD because someone read a blog post about "collaboration" and "shared understanding." They install Cucumber or SpecFlow. They write feature files. They map steps to Selenium or Playwright code. And they call it a day. But look closely at what happens next. The product owner never reads the feature files. The developer skims them once and goes back to writing code. The QA engineer — that's you — becomes the sole maintainer of a growing pile of Gherkin that nobody else touches. You're not facilitating collaboration. You're translating manual test cases into a format that requires a compiler. Here's the real test. Take any feature file from your project. Hand it to a developer who has never seen it. Ask them to implement the feature using only the Gherkin as a spec. If they can write production code from it, you have real BDD. If they ask you for clarification, you have documentation theater. I've seen teams with hundreds of feature files. Beautifully formatted. Perfect indentation. Tags for every regression cycle. And not a single one of th

2026-07-21 原文 →
AI 资讯

Your First Week of AI-Assisted Automation Will Be a Debugging Nightmare

Most engineers expect AI-assisted automation to be the easy part. You describe a test, the model writes it, you move on. The first week will prove you wrong. Not because the code is bad. Because the code is almost right. And almost-right code is harder to debug than wrong code. Wrong code fails loudly. Almost-right code passes on Monday, fails on Tuesday, passes again on Wednesday, and by Thursday you are questioning whether you understand your own application. I have watched teams adopt AI copilots into their Playwright suites and spend the first five days doing nothing but untangling false passes. If you are about to start this journey, here is what that week actually looks like. The Problem: The Model Does Not Know What "Stable" Means A language model has never waited for a network response. It has never watched a flaky selector survive three CI runs and then collapse on the fourth. It writes tests from a static understanding of your page, not from the dynamic reality of your application. You will ask it to write a test that clicks a button and waits for a confirmation toast. The model will produce something like this: await page . click ( ' button:has-text("Submit") ' ); await page . waitForSelector ( ' .toast-success ' ); Looks fine. Runs fine. Then your team deploys a new build where the toast takes 400ms longer to appear because of an analytics call. The test fails. Not because the feature broke. Because the model assumed a timing that was never guaranteed. This is the core problem. The model writes tests that match the page as it was when the model saw it . It does not write tests that match the page as it will be . The Solution: Treat AI-Generated Tests as Drafts, Not Deliverables The shift is mental before it is technical. You cannot review AI-generated tests the way you review human-written tests. Human tests come with intent. AI tests come with patterns. You need a different review lens. First, look for every hardcoded wait. Replace it with a state-based

2026-07-21 原文 →
AI 资讯

China’s AI models have Trump’s AI world at war with itself

This story originally appeared in The Algorithm, our weekly newsletter on AI. To get stories like this in your inbox first, sign up here. Over the weekend, several current and former advisors to President Donald Trump on AI publicly lobbed insults at the country’s leading AI companies. David Sacks, the president’s AI and crypto “czar” until…

2026-07-21 原文 →
AI 资讯

Judge pauses Paramount’s attempt to buy Warner Bros. Discovery

A judge partially granted the request from a dozen state attorneys general to temporarily place the $110 billion merger of Paramount and Warner Bros. Discovery on hold, as reported by Variety and Reuters. US District Judge Araceli Martínez-Olguín said that based on the new company's market share, "the Court is persuaded that it can presume […]

2026-07-21 原文 →
AI 资讯

LG’s glossy OLED gaming monitor is rare to find under $400

If you’ve been thinking about upgrading your gaming monitor, LG’s 27-inch 27GX704A-B pairs a glossy WOLED panel with a fast refresh rate, and it’s currently on sale for $379.99 (about $70 off) at Amazon and directly from LG, marking a new low price. It originally launched at $799.99, but has been available for under $500 since […]

2026-07-21 原文 →
AI 资讯

State Encryption in OpenTofu: How It Works and How to Roll It Out

If you've ever cat -ed a Terraform or OpenTofu state file, you already know the uncomfortable truth: it's a plaintext JSON dump of everything your infrastructure knows, including secrets. Database passwords, generated private keys, API tokens injected through providers — they all land in state, in the clear. OpenTofu is the one place where you can fix this at the source, because native state and plan encryption is a first-class OpenTofu feature that upstream Terraform does not have. Here's how it actually works and how I roll it out on existing projects without breaking them. Why plaintext state is a real risk State is not a cache you can regenerate. It's the authoritative map between your HCL and the real resources, and OpenTofu has to store the values of attributes to compute diffs. That includes sensitive ones. Marking an output sensitive = true only hides it from the CLI output — it's still written verbatim to state. On real infra I've seen state end up in three places it shouldn't: an S3 bucket without SSE and with overly broad read IAM, a CI artifact that got uploaded to a build cache, and a developer laptop with terraform.tfstate committed to a feature branch by accident. Backend encryption (like S3 SSE) helps for one of those. It does nothing for the other two, because the moment state leaves the backend it's plaintext again. OpenTofu's encryption operates at the data layer, before the bytes ever hit the backend or a local file. The state is encrypted at rest everywhere: in the backend, in local copies, in CI artifacts. That's the property I want. Anatomy of the encryption block Encryption lives in a terraform { encryption { ... } } block. It has three moving parts: a key provider (where the encryption key comes from), a method (the actual cipher), and targets ( state and/or plan ) that bind a method to what you want encrypted. terraform { encryption { key_provider "pbkdf2" "passphrase" { passphrase = var . tofu_encryption_passphrase } method "aes_gcm" "defa

2026-07-20 原文 →
AI 资讯

I got tired of running 4 browser extensions, so I built one

I had a website blocker, a Pomodoro timer, a tab suspender, and a time tracker installed at the same time — four separate extensions, four separate settings pages, none of them talking to each other. Starting a focus session meant manually turning on the blocker, then starting the timer, and neither knew the other existed. So I built TabInsights , which does all four and actually connects them. What it does Website blocker — block by domain, category, or schedule, with an optional typed "unblock challenge" for the days willpower isn't enough. Pomodoro focus timer — one click starts a 15/25/45-minute sprint, which also auto-blocks distracting categories for the duration and unblocks them automatically when it ends. This is the part that actually solves my original problem — the timer and the blocker are the same feature, not two extensions coincidentally running at once. Memory saver — auto-suspends tabs you haven't touched in a configurable window (15–60 min), freeing roughly 50MB of RAM each via chrome.tabs.discard() . Suspended tabs stay in your tab bar and reload exactly where you left off with one click. Automatic time tracking — logs time per domain with no manual start/stop, and shows a daily focus score. A few implementation notes Manifest V3 removed persistent background pages, which meant every "ongoing" feature — sprint timers, the daily summary, auto-suspend checks, license re-validation — had to be rebuilt on chrome.alarms instead of a long-lived timer. The gotcha: Chrome clamps alarm intervals to a minimum of 1 minute in packaged (published) extensions, so anything needing finer granularity has to accept that floor rather than fight it. The blocker uses declarativeNetRequest — you hand Chrome a set of match rules and it enforces them at the browser level. The extension never actually reads the blocked request; it can't, by design, which is also the honest answer any time someone asks whether a blocker "sees" their browsing. The bigger architectural deci

2026-07-20 原文 →
AI 资讯

How We Split a Legacy Monolith Into Microservices Without a Single Outage

8 min read · telecom provisioning platform, 30M+ subscribers Most companies avoid migrating their monolith for one reason: they imagine it as a single, terrifying event — months of a feature freeze, a weekend cutover, and a rollback plan that's really just hope. That fear is reasonable. A big-bang rewrite of a live system serving 30M+ subscribers really would be terrifying. So we didn't do that. We used a pattern that lets you migrate a monolith one slice at a time, while the system keeps running and the product team keeps shipping features — the same pattern Martin Fowler named Strangler Fig , after the vine that grows around a host tree, gradually taking over, until eventually the original tree is no longer needed. Why the "just rewrite it" instinct is usually wrong The instinct to rewrite a legacy monolith from scratch is understandable — the old code is scary, undocumented, and nobody wants to touch it. But a full rewrite has a well-known failure pattern: it takes far longer than estimated, the business can't freeze feature development for that long, and by the time the rewrite is "done," the old system has changed underneath it and the rewrite is already out of date. The alternative isn't "don't migrate." It's: migrate in slices small enough that each one is boring , and never require the business to stop shipping while you do it. The pattern: a facade, and one slice at a time Strangler Fig works by putting a routing layer — a facade or API gateway — in front of the monolith. At first, 100% of traffic passes through to the old system untouched. Then, one capability at a time: Build the new version of that one capability as an independent service. Update the facade to route just that capability's traffic to the new service. Run both in parallel long enough to trust the new one (see "shadow traffic" below). Retire that piece of the old monolith. Repeat for the next capability. At every point in this process, the system is fully functional. There's no "half-migrat

2026-07-20 原文 →